TypeScript中keyof无法提取继承带索引签名接口的显式命名键如何解决
问题根因
你遇到的现象是TypeScript的索引签名合并规则导致的:带有[key: string]: any这类字符串索引签名的接口,其keyof返回值会包含通用的string | number类型(JS中数字索引会被隐式转为字符串,因此TS的字符串索引默认兼容数字键),和子接口显式声明的字面量键合并后,字面量会被宽泛的string类型吞掉,最终只能拿到string | number。
解决方案
可以通过自定义条件类型过滤掉索引签名对应的通用string、number类型键,仅保留显式声明的字面量键:
// 自定义工具类型:提取接口的显式声明键,排除索引签名的通用键 type GetExplicitKeys<T> = { [K in keyof T]: string extends K ? never : number extends K ? never : K } extends { [_ in keyof T]: infer U } ? U : never // 不可控的外部接口 interface T1 { [key: string]: string } // 可控且必须继承T1的接口 interface T2 extends T1 { a: string b: string } // 提取得到类型为 "a" | "b" type T3 = GetExplicitKeys<T2>
进阶场景
如果你需要同时排除父接口T1自身的显式声明键,仅保留T2新增的显式键,可以再搭配内置的Exclude类型使用:
// 假设父接口T1有自己的显式键 interface T1 { [key: string]: string baseField: string } interface T2 extends T1 { a: string b: string } // 提取得到类型为 "a" | "b",自动排除父接口的baseField和索引签名键 type T3 = Exclude<GetExplicitKeys<T2>, keyof T1>
内容的提问来源于stack exchange,提问作者itslittlejohn
相关产品推荐
相关产品推荐

