TypeScript泛型函数返回Formatter<T>类型时索引类型报错求助
解决TypeScript泛型函数Formatter类型索引错误问题
场景重现
定义的类型与工具类型
type Device = { manufacturer: string; price: number; releaseYear: number; }; type Accessory = { color: string; size: number; }; type Formatter<T> = { [Key in keyof T as `format${Capitalize<Key & string>}`]: ( value: T[Key] ) => string; };
报错的泛型函数代码
const getFormatted = <T>(obj: T): Formatter<T> { const newObj: Formatter<T> = {}; Object.keys(obj).forEach((key) => { newObj[`format${capitalize(key)}`] = () => obj[key]; }) return newObj; } const { formatColor, formatSize } = getFormatted<Accessory>({ color: "#fff", size: 2 })
错误信息
Element implicitly has an 'any' type because expression of type '`format${string}`' can't be used to index type 'Formatter<T>'
问题核心
TypeScript无法将format${string}动态字符串与Formatter<T>的键类型建立关联:
Object.keys(obj)返回的是string[],而非精确的keyof T类型- 自定义
capitalize函数缺少类型约束,导致生成的键无法被识别为Formatter<T>的合法索引
修正方案
1. 实现类型安全的capitalize函数
先补全运行时的首字母大写逻辑,同时保证类型匹配:
function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); }
2. 修正泛型函数的类型断言与逻辑
const getFormatted = <T extends Record<string, unknown>>(obj: T): Formatter<T> => { // 初始空对象断言为Formatter<T>类型 const newObj = {} as Formatter<T>; // 将Object.keys的结果断言为keyof T数组,明确键的类型 (Object.keys(obj) as (keyof T)[]).forEach((key) => { const keyStr = key as string; // 生成格式化键并断言为Formatter<T>的合法键 const formattedKey = `format${capitalize(keyStr)}` as keyof Formatter<T>; // 赋值格式化函数,确保返回值为string,同时断言类型匹配 newObj[formattedKey] = (() => { const value = obj[key]; return typeof value === 'string' ? value : String(value); }) as Formatter<T>[typeof formattedKey]; }); return newObj; };
3. 测试调用
const { formatColor, formatSize } = getFormatted<Accessory>({ color: "#fff", size: 2 }); console.log(formatColor()); // 输出 "#fff" console.log(formatSize()); // 输出 "2"
关键说明
- 用
Record<string, unknown>约束泛型T,确保输入对象的键均为字符串类型 - 通过类型断言将动态生成的键与
Formatter<T>的键类型绑定,消除索引错误 - 格式化函数中统一将值转为字符串,严格匹配
Formatter<T>的返回值要求
内容的提问来源于stack exchange,提问作者Narek Hovsepyan
相关产品推荐
相关产品推荐

