TypeScript泛型如何生成返回值含void|never联合的函数类型
TypeScript泛型生成
()=>void|never类型问题解答 问题复现
复现问题的示例代码如下:
type UnionWithNever = void|never // 类型推导结果为void type Fn = ()=>void|never // 类型推导结果为()=>void|never,可明确表示函数要么返回void,要么抛出错误 type GenericFn<T> = ()=>T type GFn = GenericFn<void|never> // 期望得到()=>void|never类型,实际推导结果为()=>void
现象背后的类型规则
这个不一致的推导行为来自TypeScript三个核心规则的共同作用:
never类型的自动吸收规则:never代表不存在任何可能的值,因此never和任何类型组成联合类型时,都会被自动消去,即T | never等价于T。普通类型定义场景下会立刻触发这个简化,因此void|never会被直接推导为void。- 函数返回值位置的特殊保留逻辑:当开发者直接在函数类型的返回值位置书写包含
never的联合类型时,TypeScript会保留这个类型结构,作为开发者显式标记「函数可能抛出错误、无法正常返回」的意图提示,不会立刻触发never吸收简化。 - 泛型实例化的归一化逻辑:当把
void|never作为泛型参数传入时,TypeScript会先对传入的类型参数做归一化处理,也就是先执行never吸收把类型简化为void,再代入泛型定义替换类型变量,最终得到的自然是()=>void。
实现方案
要让泛型生成目标的()=>void|never类型,核心思路是绕过泛型实例化时的提前类型简化,可选方案如下:
- 方案1:使用分布式条件类型延迟类型计算
type GenericFn<T> = () => T extends unknown ? T : never type GFn = GenericFn<void|never> // 推导结果为() => void | never
条件类型会在泛型实例化时触发分布式计算,不会提前对传入的联合类型做never吸收简化,会保留完整的联合结构放到返回值位置。
- 方案2:使用元组包装类型参数
type GenericFn<T extends readonly any[]> = () => T[number] type GFn = GenericFn<[void, never]> // 推导结果为() => void | never
元组内部存储的类型不会触发联合类型的提前简化,通过T[number]提取元组所有成员构成联合类型,直接放在返回值位置即可得到和手写定义一致的效果。
内容的提问来源于stack exchange,提问作者TrevTheDev
相关产品推荐
相关产品推荐

