TypeScript实现泛型接口时类型不匹配未报错的原因与解决方法
TypeScript类实现泛型接口时方法参数类型兼容问题解答
现象原因
这个现象是TypeScript类型系统的方法参数双变检查规则,以及类型安全设计共同导致的:
- 首先泛型接口
IType<T>约定的是调用侧契约:只要是IType<IArgs1>类型的实例,调用configure方法时必须传入同时包含a、b属性的IArgs1类型参数,这个约束不会被打破。 - TypeScript对类方法的参数默认采用双变(bivariance)检查:只要实现方法的参数类型和接口定义的参数类型存在父子兼容关系,就判定为合法。
- 你示例中的
IArgs2是IArgs1的父类型(IArgs1包含IArgs2的所有属性,属于IArgs2的子类型),实现方法用父类型作为参数是完全安全的:调用侧一定会传入满足IArgs1的参数,自然也满足IArgs2的要求,实现方法永远不会读取到不存在的属性,因此不会报错。 - 而
IArgs3和IArgs1没有父子兼容关系,IArgs1不包含IArgs3要求的d属性,如果实现方法用IArgs3作为参数,运行时可能读取到不存在的属性,因此TS会抛出错误。
- 你示例中的
强制参数类型完全一致的方案
你可以通过修改接口定义+开启严格编译选项实现严格匹配:
- 首先开启
tsconfig.json中的strictFunctionTypes配置项(属于strict模式的子配置,开启后会对函数参数启用严格逆变检查) - 将接口中的方法定义修改为函数属性写法,触发严格检查:
interface IType<T> { // 把方法写法改成函数属性写法 configure: (args: T) => void }
修改后你再用IArgs2作为configure的参数类型,TS就会直接抛出类型不匹配的错误。
如果不想修改全局编译配置,也可以用工具类型做实现校验:
type StrictMatch<Impl, Interface> = Impl extends Interface ? Interface extends Impl ? unknown : { "参数类型不匹配": never } : { "参数类型不匹配": never } class Class implements IType<IArgs1> { configure(args: IArgs2) {} } // 校验不通过会抛出错误 type _Check = StrictMatch<Class, IType<IArgs1>>
内容的提问来源于stack exchange,提问作者Nickon
相关产品推荐
相关产品推荐

