TypeScript中泛型类型拓宽的更优雅实现方案
优化TypeScript
get函数的默认值类型拓宽实现 问题背景
需要实现一个get函数,满足:
- 传入默认参数时,函数返回值类型为该参数的拓宽类型(例如传入字面量
'bar'时,返回string而非'bar') - 未传入默认参数时,返回值类型为
any
初始实现的get函数中,泛型TDefault会捕获默认值的字面量类型,导致返回类型被限制为字面量,不符合预期:
export const get = <TDefault = unknown>(value: object, path: string, defaultValue?: TDefault) { // 函数逻辑 }
现有解决方案通过自定义ToPrimitive类型手动实现类型拓宽,但写法繁琐冗余:
export type ToPrimitive<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends undefined ? object : keyof T extends never ? object : T extends object ? T : any export const get = <TDefault = unknown>(value: object, path: string, defaultValue?: TDefault): ToPrimitive<TDefault> { // 函数逻辑 }
更优雅的实现方案
方案1:简化基础类型拓宽逻辑
针对基础字面量类型做精准拓宽,对象类型直接保留原类型(若需拓宽对象属性的字面量类型,可进一步扩展):
// 定义类型拓宽工具 type WidenType<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends null ? null : T extends undefined ? undefined : T; // 对象/其他类型直接保留 export const get = <TDefault = any>(value: object, path: string, defaultValue?: TDefault): WidenType<TDefault> { // 函数逻辑 }
方案2:简洁自动拓宽实现
通过infer结合条件类型,让TypeScript自动完成类型拓宽,写法更紧凑:
type Widen<T> = T extends infer U ? U extends string ? string : U extends number ? number : U extends boolean ? boolean : U : never; export const get = <TDefault = any>(value: object, path: string, defaultValue?: TDefault): Widen<TDefault> { // 函数逻辑 }
方案3:深层对象属性拓宽(可选)
如果需要对传入的对象默认值的属性字面量也进行拓宽,可使用递归类型:
type DeepWiden<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends null ? null : T extends undefined ? undefined : T extends object ? { [K in keyof T]: DeepWiden<T[K]> } : T; export const get = <TDefault = any>(value: object, path: string, defaultValue?: TDefault): DeepWiden<TDefault> { // 函数逻辑 }
说明
- 将泛型默认值从
unknown改为any,满足未传入默认参数时返回any的需求 - 简化后的类型工具逻辑更清晰,避免了冗余的条件分支
- 可选的深层拓宽方案可根据实际业务需求选择使用
内容的提问来源于stack exchange,提问作者Stefaan
相关产品推荐
相关产品推荐

