You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中为何用[M] extends [never]包裹泛型?Redux Toolkit解析

为什么Redux Toolkit的PayloadAction要用元组包裹泛型做extends判断?

先看Redux Toolkit中PayloadAction的源码:

export type PayloadAction<
  P = void,
  T extends string = string,
  M = never,
  E = never
> = {
  payload: P
  type: T
} & ([M] extends [never]
  ? {}
  : {
      meta: M
    }) &
  ([E] extends [never]
    ? {}
    : {
        error: E
      })

核心原因:规避TypeScript分布式条件类型对never的特殊处理

直接用M extends never会触发分布式条件类型,而never作为空联合类型,会导致整个条件判断的结果不符合预期:

  1. 分布式条件类型的特性:当条件类型的左侧是裸泛型参数(没有被包裹在元组、对象等结构里),且该参数是联合类型时,TypeScript会把条件逻辑分别应用到联合类型的每个成员上,再把结果合并成新的联合类型。
  2. never的特殊表现:never是没有任何成员的联合类型,当裸泛型参数M等于never时,M extends never ? A : B会因为没有可遍历的成员,最终返回never,而不是我们想要的A(即{})。

具体后果(你的错误示例)

当你把判断改成M extends never后:

export type PayloadAction<
  P = void,
  T extends string = string,
  M = never,
  E = never
> = {
  payload: P;
  type: T;
} & ( M extends never
  ? {}
  : {
      meta: M;
    }) &
  ([E] extends [never]
    ? {}
    : {
        error: E;
      });

在示例中传入M=never时,M extends never的结果是never,原对象类型{payload: void, type: 'FAILURE'}和never交叉后,整个PayloadAction类型会变成never——这就是为什么你创建的errorAction会提示“无法赋值给类型never”。

元组包裹的作用

用[M] extends [never]时,[M]是一个元组类型,不是裸泛型参数,因此不会触发分布式条件类型。此时判断的是“由M组成的元组是否等于由never组成的元组”:

  • 如果M=never,则[never] extends [never]为true,返回{},和原对象交叉后不改变类型;
  • 如果M是其他类型(比如string),则[string] extends [never]为false,返回{meta: M},从而为Action添加meta属性。

同理,[E] extends [never]也是为了正确判断E是否为never,避免同样的问题。

内容的提问来源于stack exchange,提问作者talpx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:36:21