【问题标题】:Using mapped types in TypeScript to restrict method types在 TypeScript 中使用映射类型来限制方法类型
【发布时间】:2018-10-26 14:12:38
【问题描述】:

我想在 TypeScript 中实现一个订阅/发布类。问题是每种事件类型都有不同的数据类型,我无法弄清楚如何以静态类型的方式进行操作。这是我目前拥有的:

type EventType = "A" | "B" | "C"

interface EventPublisher {  
    subscribe(eventType: EventType, callback: (data: any) => void);
    publish(eventType: EventType, data: any);
}

有没有办法摆脱 any 并以某种方式执行此操作,以便当我使用类型(例如 X)实例化 eventPublisher 时,subscribepublish 方法的行为如下?

interface X {
    "A": number;
    "B": string;
}

const publisher: EventPublisher<X> = ...;
publisher.publish("A", 1); // OK!
publisher.publish("A", "blah"); // Error, expected number by got string

我可以这样定义接口签名:

interface EventPublisher<U extends { [key in EventType]? : U[key] }>

但无法弄清楚如何将 U[key] 与方法中的 data 类型联系起来。

【问题讨论】:

    标签: typescript types


    【解决方案1】:

    您需要为方法上的键添加泛型类型参数,并使用类型查询将事件类型与参数类型相关联。

    type EventType = "A" | "B" | "C"
    
    interface EventPublisher<T extends { [ P in EventType]? : any }> {  
        subscribe<E extends EventType>(eventType: E, callback: (data: T[E]) => void): void;
        publish<E extends EventType>(eventType: E, data: T[E]) : void;
    }
    
    interface X {
        "A": number;
        "B": string;
    }
    
    const publisher: EventPublisher<X> = ...;
    publisher.publish("A", 1); // OK!
    publisher.publish("A", "blah"); //error
    

    【讨论】:

    • @Titan 关于您的解决方案的两个问题。首先,现在我可以添加一个事件publisher.publish("C", null);,尽管类型 X 没有定义C。我知道这是由于 TS 的结构类型系统造成的,但最好将 E 限制为 T 的键。其次,如果我想要一个undefined 类型,比如interface X { "C" : undefined },有没有办法让data 参数可选,以便我可以调用publisher.publish("C")?如果您能就这两个问题分享您的想法,我们将不胜感激。
    • @Wickoo 您可以改用&lt;E extends keyof T&gt;,应该可以按预期工作,但我没有测试。
    • @Wickoo 如果处理程序有不同数量的参数,它会变得有点复杂。我有一个类似的答案,但参数计数任意stackoverflow.com/questions/50369299/…
    • @Titan 谢谢!第一个有效。对于第二个,需要一些思考来弄清楚它是如何工作的:-)
    • @Wickoo 是的.. 其他版本有点滥用类型系统,但它有效;-)。如果您的需求不那么复杂,我会坚持使用这个..
    猜你喜欢
    • 1970-01-01
    • 2018-06-25
    • 2018-02-05
    • 2020-08-07
    • 2017-08-08
    • 2019-03-21
    • 1970-01-01
    • 2019-01-27
    • 2018-04-04
    相关资源
    最近更新 更多