TypeScript中实现接口时用非完整交叉类型作方法参数为何被允许
问题原因解析
这是TypeScript类型系统中函数参数兼容性规则的正常表现,核心逻辑很容易理解:
1. 基础判断逻辑
接口System对Update方法的要求是:必须可以接收同时拥有Transform和RenderData全部属性的参数。
而RenderSystem的Update实现只要求参数满足RenderData的结构。此时所有符合接口要求的入参,天然就满足RenderData的类型要求,你的实现代码永远不会收到不符合自身参数类型声明的入参,TS认为这种写法是类型安全的,因此不会报错。
你可以用一个通俗的场景类比:
接口要求你开的餐馆必须能接待「同时带了身份证和健康码的客人」,你实际经营的餐馆只要客人带健康码就接待,当然完全符合要求,不会有任何问题。
如果把参数换成number,显然符合接口要求的对象类型根本无法兼容number,就相当于你要求客人必须是数字才能进店,自然不符合接口要求,TS就会抛出错误。
2. 什么情况会报错?
如果你的实现把Update的参数写为比接口要求更窄的类型(比如增加额外必填属性):
class RenderSystem implements System { // 此处会直接抛出参数不兼容的错误 Update(e: RenderData & {VIP: boolean}): void {} }
此时TS会报错,因为接口允许传入没有VIP属性的参数,你的实现要求却更高,会出现运行时风险,相当于你要求客人必须是VIP才能进,不符合接口的通用要求。
3. 如何强制参数完全匹配接口?
如果希望TS严格校验实现的参数必须和接口声明完全一致,可以在tsconfig.json中开启strictFunctionTypes编译选项。注意该选项默认仅对独立函数生效,如果要对类方法也开启严格校验,需要将接口中的方法定义为箭头函数形式:
interface System { Update: (e: Transform & RenderData) => void }
内容的提问来源于stack exchange,提问作者jfax
相关产品推荐
相关产品推荐

