Using Typescript to enforce a generic interface restriction on an interface?

I have 2 interface descriptions:

interface IStore    { }
interface SomethingElse     { a: number;}

And 2 classes that each implement:

class AppStoreImplemetion implements IStore 
 { }

class SomethingImplementation  implements SomethingElse
 {
    a: 4;
 }

I want my method to get the return type as a "must have IStore" constraint , so I did this:

class Foo {

    selectSync<T extends IStore>( ):  T
        {
        return <T>{/* omitted*/ };    // I set the return type(`T`) when invoking
        }
}

Ok

Testing:

This works as expected:

new Foo().selectSync<AppStoreImplemetion>();

But this also works - not as expected:

new Foo().selectSync<SomethingImplementation>();

Question:

How can I make my method accept a return type that should implement IStore?

Demo version

+4
source share
1 answer

, Typescript , IStore , SomethingElse

(, #/Java ..) , . , :

interface IStore { 
    __isStore: true // Field to ensure incompatibility
}
interface SomethingElse { a: number; }

class AppStoreImplemetion implements IStore { 
    __isStore!: true // not used, not assigned just there to implement IStore
}

class SomethingImplementation implements SomethingElse {
    a = 4;
}

class Foo {

    selectSync<T extends IStore>(): T {
        return <T>{/* omitted*/ };   
    }
}

new Foo().selectSync<AppStoreImplemetion>();
new Foo().selectSync<SomethingImplementation>(); // This will not be an error

, , __isStore, , , IStore, - , Typescript , :

class SomethingImplementation implements SomethingElse {
    a = 4;
    __isStore!: true 
}
new Foo().selectSync<SomethingImplementation>(); // now ok

IStore, , , .

100% - , , IStore . , :

abstract class IStore { 
    private __isStore!: true // Field to ensure incompatibility
}
interface SomethingElse { a: number; }

class AppStoreImplemetion extends IStore { 

}
class Foo {

    selectSync<T extends IStore>(): T {
        return <T>{/* omitted*/ };   
    }
}

new Foo().selectSync<AppStoreImplemetion>(); // ok 

class SomethingImplementation implements SomethingElse {
    private __isStore!: true;
    a = 10;
}
new Foo().selectSync<SomethingImplementation>(); // an error even though we have the same private since it does not extend IStore
+4

Source: https://habr.com/ru/post/1695503/


All Articles