TypeScript:如何从带字符串索引的接口获取非索引成员类型
如何排除接口的字符串索引签名并优化泛型函数的类型显示?
我定义了一个包含字符串索引签名的接口:
interface Parent { child_1: number; child_2: string; [key: string]: any; }
现在需要实现一个泛型函数func,要求参数类型只包含接口里显式定义的属性类型(也就是number | string),需要排除掉[key: string]: any这个索引签名。
目前我有两种实现方式,但都存在缺陷:
方案一:类型别名封装,但hover无具体类型
type NoStringIndex<U> = { [K in keyof U as string extends K ? never : K]: U[K]; }; type Children<T> = NoStringIndex<T>[keyof NoStringIndex<T>]; const func = <T>(children: Children<T>) => {/* 处理T的成员类型 */}调用
func<Parent>("hej")时,hover函数只能看到const func: <Parent>(children: Children<Parent>) => void,无法直接看到具体的string | number类型,调试体验不好。方案二:直接写类型表达式,hover有具体类型但代码冗余
type NoStringIndex<U> = { [K in keyof U as string extends K ? never : K]: U[K]; }; const func = <T>(children: NoStringIndex<T>[keyof NoStringIndex<T>]) => {/* 处理T的成员类型 */}这种写法hover时能显示
const func: <Parent>(children: string | number) => void,但如果需要在多个地方复用这个类型,重复写长表达式会导致代码不够简洁。
最优解决方案
我们可以通过**Prettify类型强制展开别名**,或者利用TypeScript的条件类型推导,兼顾代码复用和类型显示的需求:
方法一:使用Prettify展开类型别名
// 辅助类型:强制TypeScript展开嵌套/别名类型,显示具体结构 type Prettify<T> = T extends infer U ? { [K in keyof U]: U[K] } : never; // 过滤掉接口中的字符串索引签名 type OmitStringIndex<T> = { [K in keyof T as string extends K ? never : K]: T[K]; }; // 提取过滤后的属性值联合类型,通过Prettify让hover时显示具体类型 type Children<T> = Prettify<OmitStringIndex<T>[keyof OmitStringIndex<T>]>; const func = <T>(children: Children<T>) => {/* 处理T的成员类型 */}
方法二:利用条件类型推导(TypeScript 5.0+)
如果你的项目使用TypeScript 5.0及以上版本,可以省略Prettify类型,直接通过条件推导让类型自动展开:
type OmitStringIndex<T> = { [K in keyof T as string extends K ? never : K]: T[K]; }; type Children<T> = keyof OmitStringIndex<T> extends infer K ? K extends keyof T ? T[K] : never : never; const func = <T>(children: Children<T>) => {/* 处理T的成员类型 */}
两种方法都能实现:调用func<Parent>("hej")时,hover函数会显示const func: <Parent>(children: string | number) => void,既保证了代码的复用性,又能看到清晰的具体类型。
内容的提问来源于stack exchange,提问作者Erik
相关产品推荐
相关产品推荐

