如何解决Enum类型作为键时的类型识别错误?需保留类型提示
解决TypeScript枚举作为对象键时的路径类型识别问题
问题核心
当对象使用字符串枚举作为计算属性键时,现有的Path和PathValue类型无法正确识别形如'bar.width'的字符串路径,导致类型推导失败(如示例中的t2测试不通过),但普通字符串键的路径(如'bar.foo.baz')可以正常工作。
问题原因
- 原代码中
PathImpl的Key extends string条件会排除枚举成员类型(字符串枚举的成员类型并非string,而是独特的枚举成员类型),导致生成的路径集合中不包含枚举键对应的字符串路径。 PathValue在解析字符串路径时,无法将字符串形式的键(如'width')映射到对应的枚举成员键(如style.WIDTH),从而无法正确获取属性类型。
解决方案
通过模板字符串类型的特性,将枚举成员类型转换为对应的字符串值类型,同时修改路径生成和值解析的逻辑,确保字符串路径能正确匹配枚举键。
修改后的完整代码
type IsAny<T> = unknown extends T ? [keyof T] extends [never] ? false : true : false; /* eslint-disable @typescript-eslint/no-explicit-any */ export type PathImpl<T, Key extends keyof T> = `${Key}` extends string ? IsAny<T[Key]> extends true ? never : T[Key] extends Record<string, any> ? | `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof any[]>>}` | `${Key}.${Exclude<keyof T[Key], keyof any[]>}` : never : never; /* eslint-enable @typescript-eslint/no-explicit-any */ export type PathImpl2<T> = PathImpl<T, keyof T> | `${keyof T}`; export type Path<T> = `${keyof T}` extends string ? PathImpl2<T> extends infer P ? P extends string ? P : `${keyof T}` : `${keyof T}` : never; type GetValueByStringPath<T, P extends string> = P extends `${infer Key}.${infer Rest}` ? ( K extends keyof T ? `${K}` extends Key ? GetValueByStringPath<T[K], Rest> : never : never ) extends infer V ? V extends never ? never : V : never : ( K extends keyof T ? `${K}` extends P ? T[K] : never : never ) extends infer V ? V extends never ? never : V : never; export type PathValue<T, P extends Path<T>> = GetValueByStringPath<T, P extends string ? P : `${P}`>; enum style { HEIGHT = 'height', WIDTH = 'width' } type Props = { foo: string; bar: { street: string; [style.HEIGHT]: string; [style.WIDTH]: string; foo: { baz: number; } }; }; declare function useProp<P extends Path<Props>>(path: P): PathValue<Props, P>; import type { Equal, Expect } from '@type-challenges/utils' // 测试通过 type t1 = Expect<Equal<PathValue<Props, 'bar.foo.baz'>, number>> // 现在测试通过 type t2 = Expect<Equal<PathValue<Props, 'bar.width'>, string>>
关键修改点说明
路径生成逻辑:
- 将
PathImpl中的Key extends string改为${Key} extends string,利用模板字符串类型自动将枚举成员转换为对应字符串值的特性,确保枚举键能被纳入路径生成。 PathImpl2和Path中统一使用${keyof T}将所有键转换为字符串类型,保证路径集合的一致性。
- 将
值解析逻辑:
- 新增
GetValueByStringPath类型,通过匹配字符串路径与对象键的字符串表示(${K}extends P),将字符串路径映射到对应的对象键(包括枚举键),从而正确推导属性类型。 PathValue基于GetValueByStringPath实现,确保字符串路径能正确解析到对应的属性值类型。
- 新增
验证效果
- 原测试
t1保持通过,t2现在也能正常通过。 - 保留完整的路径提示功能:在调用
useProp时,输入路径会自动提示所有合法的字符串路径,包括枚举键对应的'bar.height'、'bar.width'等。
内容的提问来源于stack exchange,提问作者peter roe
相关产品推荐
相关产品推荐

