如何强制函数参数匹配对象的键名与类型?
解决方案
你的写法逻辑本身是正确的,但之所以没生效,是因为I<T>是空类——TypeScript采用结构类型系统,空类的不同泛型实例会被判定为兼容(因为它们的结构完全一致),所以无法区分I<number>和I<string>。
要实现预期的类型约束,只需给I<T>添加一个带有泛型类型的私有成员,让不同泛型参数的I类型形成不兼容的名义类型:
class I<T> { // 添加私有泛型属性,让不同T的I实例类型不兼容 private _marker?: T; } class W<T extends object> { field<K extends keyof T>(key: K, val: I<T[K]>) { void 0; } } class A { i: number = 3; s: string = "test"; } let Winstance: W<A> = new W<A>(); Winstance.field("i", new I<number>()); // OK Winstance.field("s", new I<number>()); // 类型错误(符合预期) Winstance.field("i", new I<string>()); // 类型错误(符合预期) Winstance.field("s", new I<string>()); // OK
原理说明
TypeScript对包含私有成员的类会启用名义类型检查:只有同一个类构造出来的实例,且泛型参数匹配时,才会被视为兼容类型。添加私有泛型属性_marker后,I<number>和I<string>的结构因私有成员的类型差异而不兼容,从而实现了val类型与key对应属性类型的绑定。
内容的提问来源于stack exchange,提问作者Javaddict
相关产品推荐
相关产品推荐

