javascript - 使用 Typescript 强制接口(interface)的通用约束?

标签 javascript typescript

我有 2 个接口(interface)声明:

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

还有 2 个实现每个类的类:

class AppStoreImplemetion implements IStore 
 { }

class SomethingImplementation  implements SomethingElse
 {
    a: 4;
 }

我希望我的方法被赋予返回类型作为 "must be IStore"的约束,所以我这样做了:

class Foo {

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

好的

测试:

这按预期工作:

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

但这也有效 - 如预期的那样:

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

问题:

如何强制我的方法接受必须实现 IStore 的返回类型?

Online demo

最佳答案

问题是 Typescript 使用结构类型来确定类型兼容性,因此接口(interface) IStore 是空的,与任何其他类型兼容,包括 SomethingElse

模拟标称类型(C#/Java 等中的类型)的唯一方法是添加一个字段,使接口(interface)与其他接口(interface)不兼容。您实际上不必使用该字段,您只需声明它以确保不兼容:

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 be an error

请注意,任何具有 __isStore 的类都将是兼容的,无论它明确实现了 IStore,同样是由于 Typescript 使用结构来确定兼容性,所以这有效:

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

在实践中,IStore 可能会有更多的方法,所以这种偶然的兼容性应该很少见。

作为旁注,私有(private)字段确保不相关类的 100% 不兼容,因此如果有可能使 IStore 成为具有私有(private)字段的抽象类。这可以确保没有其他类意外兼容:

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

关于javascript - 使用 Typescript 强制接口(interface)的通用约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49549134/

相关文章:

javascript - 解析网页上的自由格式日期条目?

javascript - CryptoJS AES 加密输出长度

javascript - Jquery触发key.Code事件

javascript - Angularjs:使用路由参数并重新加载

javascript - RxJS:如何仅在订阅外部可观察对象/主题时订阅内部可观察对象?

typescript block 节点/模块工厂模式 : error TS4060

javascript - 在 Jquery 中隐藏和更改 div 元素

javascript - 运行导入 css 模块的 ts-node 脚本

javascript - Angular 2 - 对象属性返回为未定义,但它们存在

angular - 在 Ionic 2 中隐藏子页面中的选项卡