TypeScript设置config正确类型保留泛型键的类型报错解决
报错原因
报错来自两个类型设计的问题:
- 未加约束的对象字面量里,TS会把
[fn1, fn2]这种数组字面量推断为普通可变长度数组类型(比如((a: number) => {})[]),而不是你定义的固定长度为2的元组类型ActionConfig。普通数组的长度在类型层面是不确定的,不符合ActionConfig必须有2个元素的要求,所以会提示「源类型元素可能不足」。 createActions函数里把入参actionsMap的类型直接写死为ActionsMapConfigType,一方面打断了泛型T的自动推断,另一方面哪怕你手动传入typeof config作为泛型参数,也会因为config的类型不满足元组长度要求直接报错。
修复方法
1. 调整createActions的入参类型定义
不要把actionsMap的类型写死为ActionsMapConfigType,直接使用泛型T作为入参类型,仅通过extends做结构约束,保证泛型能正确捕获传入配置的所有键和函数类型:
export const createActions = <T extends ActionsMapConfigType>( prefix: string, actionsMap: T ): ActionMapType<T> => { const result: Partial<ActionMapType<T>> = {}; for (const [key, value] of Object.entries(actionsMap)) { const [payloadCreator, metaCreator] = value; result[key as keyof ActionMapType<T>] = (...args: any[]) => ({ type: `${prefix}_${key}`, payload: payloadCreator(...args), meta: Object.assign({}, metaCreator(...args)), }) } return result as ActionMapType<T>; };
2. 给config添加类型约束,固定元组类型
不要直接写裸的对象字面量,也不要直接给config标注ActionsMapConfigType类型(会丢失具体键和参数的类型信息),根据你的TS版本选下面任意一种方式:
- TS 4.9及以上版本(推荐):用
satisfies关键字做结构校验,不会修改原值的推断类型,能完整保留所有键和函数的类型信息:
const config = { test: [ (a: number) => ({}), (a: number, b: string) => ({}), ] } satisfies ActionsMapConfigType; // 调用时不需要手动传入泛型参数,TS会自动推断所有类型 const action = createActions('form', config); // 此时action.test的参数类型会被正确推断为(a: number, b: string) => ...,类型提示完全保留
- TS 4.9以下版本:用
as const将数组字面量断言为只读元组,让TS识别到数组固定为2个元素:
const config = { test: [ (a: number) => ({}), (a: number, b: string) => ({}), ] as const } // 同样不需要手动传泛型,类型可以正常推断 const action = createActions('form', config);
注意:不要用
const config: ActionsMapConfigType = {...}这种写法,这种标注会让TS把config的类型拓宽为通用的Record结构,丢失所有自定义的键名、函数参数类型,最终返回的action也不会有精准的类型提示。
内容的提问来源于stack exchange,提问作者Valerii Zubkov
相关产品推荐
相关产品推荐

