TypeScript类实现接口时未触发缺失属性的类型校验报错
TypeScript类实现接口时参数类型“缺属性”不报错的原因
复现代码
interface IInterface2<T, C> { propA: T, propB: C } interface IInterface { doSomething(test: IInterface2<{a: number, c: string}, {b: number}>): void } class Test implements IInterface { doSomething(test: IInterface2<{ a: number },{ b: number }>): void { throw new Error("Method not implemented.") } }
原因说明
这段代码没有触发类型报错,并不是TS的检查漏洞,而是类型系统的既定设计规则导致的:
- 首先是函数参数的基础兼容性判断逻辑:TS检查方法实现是否符合接口约定时,只要求所有符合接口定义的入参,都能被实现方法正常接收,不要求参数类型和接口定义完全一致。
上述代码里,接口约定入参的propA需要包含a、c两个属性,而实现中声明的propA仅要求包含a属性——所有同时带a、c属性的对象,天然满足“存在a属性”的要求,如果方法内仅读取入参属性,这个写法是完全类型安全的,本身就不应该触发错误。
真正属于类型错误的写法是反向的:如果实现里要求入参必须包含接口没约定的额外属性,调用方按接口约定传参时就可能出现属性缺失,引发运行时异常。 - 其次是TS为兼容JS生态保留的宽松规则:如果方法内存在写入入参属性的逻辑(比如给
test.propA赋值一个仅带a属性的对象),就会破坏调用方传入的参数结构,导致后续访问c属性时拿到undefined。这种场景下TS默认不报错,是因为TS对类、接口中用方法语法声明的成员,默认开启参数双变检查,同时对普通对象的可变属性也不做严格的逆变校验。这个设计是为了适配JavaScript灵活的开发习惯,避免过度严格的检查把大量日常开发中常见的合法JS代码标记为错误。
严格检查配置方案
如果需要更严格的类型校验,堵住参数写入场景下的安全漏洞,可以通过以下方式调整:
- 开启
strictFunctionTypes编译选项,同时将接口内的方法声明从方法语法改为函数属性写法,TS就会对参数执行严格的逆变校验,上述写法会直接抛出类型不兼容错误,参考写法:
interface IInterface { // 改为函数属性声明语法 doSomething: (test: IInterface2<{a: number, c: string}, {b: number}>) => void }
- 直接开启
strict全量严格检查配置集,它包含strictFunctionTypes等所有严格类型检查规则,能整体提升项目的类型安全水位。
内容的提问来源于stack exchange,提问作者Rui Araújo
相关产品推荐
相关产品推荐

