TypeScript中payload设为Partial<UserState>为何未报错?仅校验首个属性
我在TypeScript里定义UserAction类型时,把payload设为Partial<UserState>,但dispatch操作中传入包含不存在的ffff属性的payload时,TypeScript并未触发报错,而且看起来仅校验了第一个属性loading。正常情况下TS应该对此类非法属性报错,我检查了Redux的ThunkAction类型未发现问题,有没有人遇到过类似情况?
代码示例
type UserState = { user: User | null; loading: boolean; error: Error | null } type UserAction = { type: typeof SET_USER; payload: Partial<UserState>; }; type ActionUser = SetDetailedUserAction; const fetchUser = ( id: string, ): ThunkAction< Promise<any>, RootState, any, ActionUser > => async (dispatch) => { dispatch({ type: SET_USER, payload: { loading: true, ffff: false }, /// 此处`ffff`未触发TS报错 }); }
类型别名定义错误:代码里
ActionUser被赋值为SetDetailedUserAction,但未给出该类型的定义。如果SetDetailedUserAction是一个宽松类型(比如允许任意属性),那么ThunkAction的Action参数就不是你预期的UserAction,自然不会校验非法属性。先将ActionUser替换为UserAction,测试是否触发报错。TypeScript结构类型的兼容性特性:TS采用结构类型系统,当传入的对象同时包含合法属性和额外属性时,若目标类型(
Partial<UserState>)未明确禁止额外属性,TS可能不会报错。可以通过以下方式强制校验:- 对payload进行类型断言,明确指定为
UserAction['payload']:dispatch({ type: SET_USER, payload: { loading: true, ffff: false } as UserAction['payload'], // 此时会触发非法属性报错 }); - 定义更严格的payload类型,比如自定义
Exact类型来禁止额外属性:type Exact<T, U> = T & Record<Exclude<keyof U, keyof T>, never>; type StrictUserPayload = Exact<Partial<UserState>, Partial<UserState>>;
- 对payload进行类型断言,明确指定为
ThunkAction泛型参数不匹配:ThunkAction的第四个泛型参数指定的是允许dispatch的Action类型,如果
ActionUser不是准确的UserAction,dispatch就不会按照UserAction的规则校验。直接将该参数替换为UserAction,确认是否解决问题。未启用严格类型检查:检查
tsconfig.json是否开启了strict: true配置。若严格模式未启用,TS的类型校验会大幅放宽,可能忽略这类非法属性问题。开启严格模式后,TS会更严格地校验类型兼容性。
内容的提问来源于stack exchange,提问作者Karpenter

