TypeScript:用原始类型键索引映射类型的报错解决问询
解决TypeScript中
keyof T无法索引KeyToTransformerLookup<T>的问题 问题根源
你定义的KeyToTransformerLookup<T>是仅包含T中非string类型字段的映射类型,而keyof T包含T的所有字段(包括string类型的)。即使运行时用key in检查key是否存在于转换对象中,TypeScript的静态类型系统无法自动推导该key属于KeyToTransformerLookup<T>的键集合,因此报错。
解决方案
通过类型守卫(类型谓词)或调整类型约束,让TypeScript明确当前key的类型属于转换对象的键集合。
1. 先定义正确的映射类型
确保KeyToTransformerLookup<T>仅保留T中非string类型的字段:
// 映射类型:仅针对T中非string类型的字段定义转换函数 type KeyToTransformerLookup<T> = { [K in keyof T as T[K] extends string ? never : K]: (rawValue: string) => T[K] };
2. 使用自定义类型谓词缩小key的类型
编写一个类型守卫函数,明确告诉TypeScript当前key是否属于转换对象的键:
// 类型谓词:判断key是否属于KeyToTransformerLookup<T>的键 function isTransformableKey<T>( key: keyof T, transformers: KeyToTransformerLookup<T> ): key is keyof KeyToTransformerLookup<T> { return key in transformers; } // 核心解析函数 function csvToArray<T>(csvContent: string, transformers: KeyToTransformerLookup<T>): T[] { // 简化CSV解析逻辑:拆分表头和行 const [headerLine, ...dataLines] = csvContent.trim().split('\n'); const headers = headerLine.split(',') as Array<keyof T>; return dataLines.map(line => { const rawValues = line.split(','); const result = {} as T; for (const key of headers) { const rawValue = rawValues[headers.indexOf(key)]; if (isTransformableKey(key, transformers)) { // 此时TypeScript明确key属于转换对象的键,可安全索引 result[key] = transformers[key](rawValue); } else { // 非转换字段直接赋值(string类型) result[key] = rawValue as unknown as T[keyof T]; } } return result; }); }
3. 应急方案:类型断言(谨慎使用)
如果不想写类型守卫,也可以用类型断言临时绕过检查,但要确保运行时逻辑正确:
for (const key of headers) { const rawValue = rawValues[headers.indexOf(key)]; if (key in transformers) { // 断言key属于转换对象的键 result[key] = (transformers as Record<keyof T, (val: string) => T[keyof T]>)[key](rawValue); } else { result[key] = rawValue as unknown as T[keyof T]; } }
效果验证
当你使用上述代码时,TypeScript会正确识别transformers[key]的类型,不再抛出索引错误,同时保证类型安全。
内容的提问来源于stack exchange,提问作者Christopher Fimbel
相关产品推荐
相关产品推荐

