如何修改TypeScript自定义类型MyType,仅接受基类相关字段名?
解决TypeScript自定义类型筛选特定基类相关字段名的问题
原代码的问题在于,你将不符合条件的字段类型设为never后,MyType<MyClass>最终会变成string | Valid[] | Valid | never——而never在联合类型中会被自动忽略,剩余的string类型会包含所有字符串字面量(比如"name"),导致所有键都能通过校验。
正确的类型定义
我们需要调整MyType,让它只保留那些字段类型是WhateverBaseClass或其子类数组的键名:
class WhateverBaseClass {} class Invalid { public invalidName!: string; } class Valid extends WhateverBaseClass { public validName!: string; } class MyClass { public name!: string; // 不符合:string类型 public validArray!: Valid[]; // 符合:Valid子类数组 public validField!: Valid; // 符合:Valid子类实例 public invalidField!: Invalid[]; // 不符合:Invalid非子类数组 } // 修正后的MyType type MyType<T> = { [K in keyof T]: // 判断字段是否是基类实例 T[K] extends WhateverBaseClass ? K // 判断字段是否是基类子类的数组 : T[K] extends Array<infer U> ? U extends WhateverBaseClass ? K : never : never; }[keyof T]; // 验证:仅接受"validArray"和"validField" const expectation: MyType<MyClass>[] = ["validArray", "validField"]; // 无报错,符合预期 // 以下代码会触发TypeScript错误(符合预期) // const error: MyType<MyClass>[] = ["validArray", "validField", "name", "invalidField"];
逻辑说明
- 遍历
T的所有键K,对每个键对应的类型T[K]做两层判断:- 第一层:直接判断是否是
WhateverBaseClass或其子类的实例; - 第二层:如果是数组类型,提取数组元素类型
U,判断U是否是WhateverBaseClass或其子类;
- 第一层:直接判断是否是
- 符合条件的键返回自身类型
K,不符合的返回never; - 通过
[keyof T]提取所有符合条件的键名,never会被自动排除,最终得到的是符合要求的键名联合类型("validArray" | "validField")。
内容的提问来源于stack exchange,提问作者naPham
相关产品推荐
相关产品推荐

