如何从剩余参数中推断联合类型?TypeScript泛型问题
解决TypeScript泛型剩余参数联合类型推断问题
问题背景
需要实现一个translate函数,要求:
- 以剩余参数的联合类型作为泛型判断依据
- 若剩余参数中存在至少一个非字符串/数字的元素,返回
ReactNode | ReactNode[] - 若所有剩余参数都是字符串或数字,返回
string
原代码如下:
type TTranslationResult<T> = T extends number | string ? string : ReactNode | ReactNode[]; export default function translate<T extends ReactNode = string>( key: TDictionaryKey, ...params: T[] ): TTranslationResult<T> { // 函数逻辑 }
当传入混合类型参数时:
translate( 'XXX', 'some string', <LinkText href={`foo`}> {foo} </LinkText> )
期望泛型T被推断为string | ReactNode,但实际仅推断出第一个元素的string类型。
问题原因
- 原函数中
...params: T[]的定义,会让TypeScript将T推断为所有参数的共同父类型,而非联合类型。如果第一个参数是string(且string属于ReactNode子类型),TypeScript会直接沿用默认泛型string或收窄到string,忽略后续的ReactNode类型参数。 - 原
TTranslationResult的条件判断是分布式的,若T为联合类型,会对每个分支单独判断,导致返回不符合预期的联合类型。
解决方案
步骤1:修改类型判断逻辑
使用非分布式条件类型,判断剩余参数的联合类型是否全部为字符串/数字:
// 判断联合类型是否全为number或string(非分布式) type AllStringOrNumber<T> = [T] extends [number | string] ? true : false; type TTranslationResult<T> = AllStringOrNumber<T> extends true ? string : ReactNode | ReactNode[];
步骤2:调整泛型推断方式
将泛型改为捕获剩余参数的元组类型,再通过Params[number]提取元组元素的联合类型:
export default function translate<Params extends ReactNode[] = string[]>( key: TDictionaryKey, ...params: Params ): TTranslationResult<Params[number]> { // 函数逻辑 }
效果验证
传入混合类型参数时:
Params会被推断为[string, ReactNode]Params[number]得到联合类型string | ReactNodeAllStringOrNumber<string | ReactNode>返回false,因此函数返回ReactNode | ReactNode[],符合需求
若传入全字符串/数字参数:
translate('YYY', 'hello', 123);
Params为[string, number]Params[number]为string | numberAllStringOrNumber<string | number>返回true,函数返回string,符合需求
内容的提问来源于stack exchange,提问作者Filip Konig
相关产品推荐
相关产品推荐

