TypeScript中扩展接口实例作为父接口参数为何不触发类型报错
问题解答
1. 为什么函数可以合法接收IState类型参数
这是TypeScript 结构化类型系统(鸭子类型)的特性决定的:
- TypeScript判断两个类型是否兼容,只检查目标类型需要的属性是否全部存在,传入对象携带多余属性是完全合法的。因为
IState继承自IUserData,天然包含IUserData要求的所有4个属性,满足类型匹配要求。 - 额外补充:只有你直接给
IUserData类型的参数传对象字面量时,TS才会触发「多余属性检查」报错,比如直接写testFunction({ FirstName: 'Jan', ..., isSuccess: true })会报错,但你这里传的是已经声明为IState类型的变量,不会触发这个检查。
注意:TypeScript的类型检查仅在编译阶段生效,不会改变运行时的JS代码逻辑,所以你打印的还是完整的原对象,多余属性不会被自动删除。
2. 无需手动映射的属性过滤方案
TS的类型不会影响运行时逻辑,所以可以先维护一份IUserData的属性列表,再通过通用逻辑过滤,避免手动写逐个映射的代码,实现方案如下:
// 只需要维护这一份属性数组,类型自动生成,不用重复定义接口 const userDataKeys = ['FirstName', 'LastName', 'Email', 'Password'] as const type IUserData = { [K in typeof userDataKeys[number]]: string } interface IState extends IUserData { isSuccess: boolean } const state: IState = { FirstName: 'Jan', LastName: 'Kowalski', Email: 'email', Password: 'abc', isSuccess: true } const testFunction = (userData: IUserData): void => { // 通用过滤逻辑,不需要手动逐个写属性映射 const filteredUserData = Object.fromEntries( userDataKeys.map(key => [key, userData[key]]) ) console.log(filteredUserData); } testFunction(state)
方案优势
后续要给IUserData新增或删除属性,只需要修改userDataKeys数组即可,类型会自动同步更新,不会出现类型和运行时逻辑不一致的问题,运行时输出的对象只会包含IUserData定义的4个属性。
内容的提问来源于stack exchange,提问作者user15039632
相关产品推荐
相关产品推荐

