TypeScript官方条件类型示例报错,如何修复createLabel函数?
TypeScript条件类型实现createLabel函数的类型错误问题
问题代码与报错
在学习TypeScript条件类型时,尝试实现createLabel函数,代码如下:
interface IdLabel { id: number /* some fields */; } interface NameLabel { name: string /* other fields */; } type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel; function createLabel<T extends number | string>(nameOrId: T): NameOrId<T> { const label: NameOrId<T> = (typeof nameOrId === 'number') ? { id: nameOrId }: { name: nameOrId} ; return label; }
编译时触发类型错误,错误信息:
Type '{ id: number; } | { name: string; }' is not assignable to type 'NameOrId<T>'. Type '{ id: number; }' is not assignable to type 'NameOrId<T>'.
错误原因
NameOrId<T>是依赖泛型参数T的分发条件类型,但函数内部的typeof检查属于运行时判断,TypeScript无法将这个判断逻辑和泛型T的静态类型绑定。
编译器只能确定nameOrId是number或string,但无法推导泛型T具体是number、string还是两者的联合类型。因此它会将右侧表达式的类型判定为{id: number} | {name: string},而无法确认该类型与NameOrId<T>完全等价,从而抛出类型不兼容的错误。
解决方案
方案1:类型断言
直接通过类型断言告知编译器右侧表达式的类型匹配NameOrId<T>:
function createLabel<T extends number | string>(nameOrId: T): NameOrId<T> { const label = (typeof nameOrId === 'number') ? { id: nameOrId } as NameOrId<T> : { name: nameOrId } as NameOrId<T>; return label; }
方案2:函数重载
利用函数重载明确不同输入对应的输出类型,类型提示更精准:
interface IdLabel { id: number /* some fields */; } interface NameLabel { name: string /* other fields */; } // 重载签名:定义输入输出的类型映射 function createLabel(nameOrId: number): IdLabel; function createLabel(nameOrId: string): NameLabel; // 实现签名:处理实际逻辑 function createLabel(nameOrId: number | string): IdLabel | NameLabel { return typeof nameOrId === 'number' ? { id: nameOrId } : { name: nameOrId }; }
方案3:分支判断结合类型断言
拆分条件分支,让逻辑更清晰,同时保留泛型写法:
type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel; function createLabel<T extends number | string>(nameOrId: T): NameOrId<T> { if (typeof nameOrId === 'number') { return { id: nameOrId } as NameOrId<T>; } else { return { name: nameOrId } as NameOrId<T>; } }
内容的提问来源于stack exchange,提问作者heapOverflow
相关产品推荐
相关产品推荐

