TypeScript:如何将函数返回类型索引指定为M的字符串类型?
TypeScript映射函数类型断言报错解决
问题场景
原TypeScript函数如下:
export const mappingResult = < const M extends Record<keyof T, string>, T extends Record<string, null | string | number | boolean> >( schema: M, input: T ) => { return Object.keys(input).reduce( (acc, key) => { const val = schema[key]; const inputValue = input[key]; if (val) { acc[val] = inputValue; } return acc; }, {} as { [K: string]: null | string | number | boolean } ); };
需求是将初始值的索引类型string替换为泛型M中定义的字符串类型,尝试了以下类型断言:
{} as { [K in keyof T as M[K]]: null | string | number | boolean }
但此时acc[val]出现报错,中文翻译为:
找不到参数类型为'string'的索引签名,该类型为'{ [K in keyof T as M[K]]: string | number | boolean | null; }'
解决方法
原因分析
报错核心是TypeScript无法自动推断schema[key](即val)的类型就是目标对象的键类型——Object.keys(input)返回的是string[]而非(keyof T)[],导致schema[key]被宽泛推断为string,无法匹配映射后的具体键类型。
方案一:类型断言缩小val的范围
先定义结果类型别名简化代码,再将val断言为结果类型的键:
export const mappingResult = < const M extends Record<keyof T, string>, T extends Record<string, null | string | number | boolean> >( schema: M, input: T ) => { // 定义结果类型别名 type ResultType = { [K in keyof T as M[K]]: null | string | number | boolean }; return Object.keys(input).reduce( (acc, key) => { // 将val断言为ResultType的键类型 const val = schema[key] as keyof ResultType; const inputValue = input[key]; if (val) { acc[val] = inputValue; } return acc; }, {} as ResultType ); };
方案二:优化key的类型并关联结果键
先把Object.keys的返回值断言为keyof T数组,再将val断言为结果类型的键,提升类型精确性:
export const mappingResult = < const M extends Record<keyof T, string>, T extends Record<string, null | string | number | boolean> >( schema: M, input: T ) => { type ResultType = { [K in keyof T as M[K]]: null | string | number | boolean }; // 将Object.keys结果断言为keyof T数组 return (Object.keys(input) as Array<keyof T>).reduce( (acc, key) => { const val = schema[key]; const inputValue = input[key]; if (val) { acc[val as keyof ResultType] = inputValue; } return acc; }, {} as ResultType ); };
方案三:用Record直接定义结果类型
更直观的方式是直接提取M中所有值的类型作为结果对象的键,用Record定义类型:
export const mappingResult = < const M extends Record<keyof T, string>, T extends Record<string, null | string | number | boolean> >( schema: M, input: T ) => { // 提取M中所有值的类型作为结果键 type ResultKeys = M[keyof T]; type ResultType = Record<ResultKeys, null | string | number | boolean>; return (Object.keys(input) as Array<keyof T>).reduce( (acc, key) => { const val = schema[key]; const inputValue = input[key]; if (val) { acc[val] = inputValue; } return acc; }, {} as ResultType ); };
这个方案中,ResultKeys直接对应M里的所有映射键类型,TypeScript能自动识别val属于ResultKeys,无需额外断言(若Object.keys未断言为keyof T,可能仍需对val做断言)。
内容的提问来源于stack exchange,提问作者Moon
相关产品推荐
相关产品推荐

