Redux类型兼容疑问:添加类型联合后AnyAction可赋值给IAction2的原因
为什么AnyAction能赋值给IAction2却不能赋值给IAction?
哈哈,这个问题我写Redux + TypeScript的时候也踩过坑!咱们先把你没写完的代码补全(毕竟提到了ILoadUse...,应该是几个具体的Action类型),假设你的类型定义是这样的:
// 具体的Action类型 export interface ILoadUserBegin { type: "LOAD_USER_BEGIN"; } export interface ILoadUserSuccess { type: "LOAD_USER_SUCCESS"; payload: User; } export interface ILoadUserFail { type: "LOAD_USER_FAIL"; error: Error; } // IAction是这些具体Action的联合类型 type IAction = ILoadUserBegin | ILoadUserSuccess | ILoadUserFail; // IAction2是一个更宽泛的通用Action类型 interface IAction2 { type: string; }
再回忆Redux官方的AnyAction类型定义:
interface AnyAction { type: string; [extraProps: string]: any; // 允许任意额外属性 }
现在拆解两个赋值问题的核心:
1. 为什么AnyAction不能赋值给IAction?
这其实是TypeScript的字面量类型窄化和联合类型赋值规则在起作用:
IAction是几个具体字符串字面量type的联合类型,它的type只能是"LOAD_USER_BEGIN"、"LOAD_USER_SUCCESS"、"LOAD_USER_FAIL"这三个值之一——相当于TypeScript给它加了一个“只能是这几个值”的严格限制。- 而
AnyAction的type是string类型,这是一个宽泛的“任意字符串”类型。TypeScript会较真:一个string类型的值有可能不是IAction联合里的那三个字面量(比如随便整个"UNKNOWN_ACTION")。 - 为了保证类型安全,TypeScript绝对不会允许这种“可能不匹配”的赋值,所以
AnyAction无法赋值给IAction。
2. 为什么AnyAction能赋值给IAction2?
这是TypeScript结构类型系统的核心规则在生效:
IAction2的定义只要求“有一个type属性,类型是string”,没有其他任何限制。AnyAction完全满足这个结构:它的type是string类型,就算有额外属性,IAction2也不限制(如果IAction2带索引签名的话,AnyAction的索引签名也完全匹配)。- 在结构类型系统里,只要源类型的所有必填属性都能被目标类型覆盖,就允许赋值——所以
AnyAction可以顺利赋值给IAction2。
你提到的“明明存在部分AnyAction无法赋值给IAction2”?
这里可能是你误解了:如果IAction2是{ type: string; }这种宽泛定义,那所有AnyAction的实例都符合它的结构,不存在无法赋值的情况。除非你的IAction2是带有其他必填属性的类型(比如{ type: string; payload: User; }),那确实有些AnyAction没有payload属性就无法赋值,但根据你的描述,显然IAction2是更宽松的通用类型。
总结一下:核心差异在于目标类型的具体程度——IAction是窄化的联合类型,要求type必须是特定字面量;IAction2是宽泛的通用类型,只要求type是string。AnyAction作为宽泛的“任意Action”类型,只能匹配同样宽泛的目标类型,无法匹配窄化的联合类型。
内容的提问来源于stack exchange,提问作者mikea
相关产品推荐
相关产品推荐

