TypeScript中对象键遍历另一对象属性的类型错误排查
TypeScript索引类型错误解决办法
问题代码
interface DataInterface { a: string[]; b: string[]; c: number[]; d: number[]; e: boolean[]; x: string y: number } const dataObject: DataInterface = { "a": [ "{$prefix} {$x}" ], "b": [ "temp {$x}" ], "c": [ 3.8 ], "d": [ 0, 50 ], "e": [ true, false ], "x": "world", "y": 1, } const tableArrays: {[index: string]:any} = { a: ["{$prefix} {$x}"], b: ["world {$x}"], c: [0, 50], d: [3.8], e: [true,false], } for (const tableArray in tableArrays) { dataObject[tableArray] = Array.from({ ...tableArrays[tableArray], length: 5, }) dataObject[tableArray].fill( tableArrays[tableArray][tableArrays[tableArray].length - 1], tableArrays[tableArray].length ) for (let i = 0; i < dataObject[tableArray].length; i++) { if (typeof dataObject[tableArray][i] === 'string') { dataObject[tableArray][i] = dataObject[tableArray][i].replace('{$x}', i) dataObject[tableArray][i] = dataObject[tableArray][i].replace('{$prefix}', "hello") } } if (tableArray === 'b') { dataObject[tableArray].pop() } } console.log(dataObject)
运行错误
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'DataInterface'. No index signature with a parameter of type 'string' was found on type 'DataInterface'.
尝试过的方案及问题
- 尝试断言
tableArray为DataInterface的键:
type BuildingTableKeys = keyof DataInterface; // 遍历tableArrays的键 for (const tableArray of Object.keys(tableArrays) as BuildingTableKeys[]) {...}
报错:
Conversion of type '{ [index: string]: any[]; }' to type '(keyof DataInterface)[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
转成unknown后仍出现更多错误。
- 尝试用
keyof定义tableArrays的索引:
const tableArrays: {[index: keyof DataInterface]:any}
报错:
An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
- 尝试映射类型写法:
const tableArrays: {[index in DataInterface]:any}
报错:
Type 'DataInterface' is not assignable to type 'string | number | symbol'.
正确解决办法
步骤1:给tableArrays定义正确的映射类型
先提取DataInterface中值为数组类型的键,再约束tableArrays的键和值类型与接口匹配:
// 提取DataInterface中值为数组类型的键 type DataArrayKeys = { [K in keyof DataInterface]: DataInterface[K] extends any[] ? K : never }[keyof DataInterface]; // 定义tableArrays的类型:键是DataArrayKeys,值对应DataInterface中该键的类型 const tableArrays: { [K in DataArrayKeys]: DataInterface[K] } = { a: ["{$prefix} {$x}"], b: ["world {$x}"], c: [0, 50], d: [3.8], e: [true,false], } as const; // 用as const让TS推断更精确
步骤2:安全遍历并处理类型断言
遍历过程中明确键的类型,同时针对不同字段做针对性的类型处理:
for (const tableArray in tableArrays) { const key = tableArray as DataArrayKeys; const sourceArr = tableArrays[key]; // 初始化数组并填充默认值 const newArr = Array.from({ length: 5 }, (_, i) => { return i < sourceArr.length ? sourceArr[i] : sourceArr[sourceArr.length - 1]; }); // 仅针对字符串数组做替换操作 if (key === 'a' || key === 'b') { (newArr as string[]).forEach((item, i) => { (newArr as string[])[i] = item.replace('{$x}', String(i)).replace('{$prefix}', "hello"); }); } // 处理b数组的pop操作 if (key === 'b') { newArr.pop(); } dataObject[key] = newArr as DataInterface[typeof key]; }
完整修正后的代码
interface DataInterface { a: string[]; b: string[]; c: number[]; d: number[]; e: boolean[]; x: string y: number } const dataObject: DataInterface = { "a": ["{$prefix} {$x}"], "b": ["temp {$x}"], "c": [3.8], "d": [0, 50], "e": [true, false], "x": "world", "y": 1, } // 提取DataInterface中值为数组类型的键 type DataArrayKeys = { [K in keyof DataInterface]: DataInterface[K] extends any[] ? K : never }[keyof DataInterface]; const tableArrays: { [K in DataArrayKeys]: DataInterface[K] } = { a: ["{$prefix} {$x}"], b: ["world {$x}"], c: [0, 50], d: [3.8], e: [true,false], } as const; for (const tableArray in tableArrays) { const key = tableArray as DataArrayKeys; const sourceArr = tableArrays[key]; // 初始化数组并填充默认值 const newArr = Array.from({ length: 5 }, (_, i) => { return i < sourceArr.length ? sourceArr[i] : sourceArr[sourceArr.length - 1]; }); // 处理字符串替换(仅针对a和b字段) if (key === 'a' || key === 'b') { (newArr as string[]).forEach((item, i) => { (newArr as string[])[i] = item.replace('{$x}', String(i)).replace('{$prefix}', "hello"); }); } // 移除b数组的最后一个元素 if (key === 'b') { newArr.pop(); } dataObject[key] = newArr as DataInterface[typeof key]; } console.log(dataObject)
说明
- 通过映射类型提取合法的数组键,确保
tableArrays的键只能是DataInterface中存在的数组字段,从根源避免字符串索引的类型问题。 - 遍历过程中明确键的类型,让TS能正确推断
dataObject[key]的类型。 - 针对字符串数组做针对性的类型断言,避免跨类型操作的错误。
内容的提问来源于stack exchange,提问作者Sam Dean
相关产品推荐
相关产品推荐

