如何为拼接参数的getLocale函数实现TypeScript类型检查?
解决方案
问题核心是当前类型约束错误地把key直接当作data的键,但实际data的键是key+_+locale的组合。我们可以通过模板字符串类型和泛型约束,让TypeScript正确关联key、locale与data的键结构:
const allowedLangs = ['nl', 'en'] as const; type AllowedLang = typeof allowedLangs[number]; // 提取data中所有去掉语言后缀后的基础键 type BaseKeys<T> = { [K in keyof T]: K extends `${infer Base}_${AllowedLang}` ? Base : never; }[keyof T]; function getLocale< T extends Record<`${B}_en`, any>, // 强制保证回退语言en的键存在 B extends BaseKeys<T>, L extends AllowedLang >( data: T, key: B, locale: L ): T[`${B}_${L}`] | T[`${B}_en`] | 'not-found' { // 用as keyof T做类型断言,辅助TS识别组合后的键属于data return data[`${key}_${locale}` as keyof T] ?? data[`${key}_en` as keyof T] ?? 'not-found'; } // 测试用例 const data = { name_nl: 'Naam', name_en: 'Name', age_en: 'Age' // 仅包含回退语言的键 }; // 合法调用 getLocale(data, 'name', 'nl'); // 返回'Naam' getLocale(data, 'age', 'nl'); // 回退到age_en,返回'Age' getLocale(data, 'name', 'en'); // 返回'Name' // 非法调用会触发TS报错 // getLocale(data, 'invalidKey', 'nl'); // 错误:invalidKey不是合法基础键 // getLocale(data, 'age', 'fr'); // 错误:fr不在允许的语言列表中
关键细节说明
- BaseKeys类型:遍历
data的所有键,通过模板字符串类型提取去掉_语言后缀的基础键(比如从name_nl提取name),让key参数被严格约束为这些合法基础键。 - 泛型约束T:要求
data必须包含${key}_en的键,确保回退逻辑总有值可用;如果业务要求每个基础键必须有所有语言的对应键,可以去掉Partial,改为强制约束T extends Record<${B}_${L}, any> & Record<${B}_en, any>。 - 空值合并运算符??:替换原代码的
||,避免因值为假值(如空字符串、0)错误触发回退,更贴合“键不存在才回退”的逻辑。 - 类型断言:由于TypeScript暂时无法自动推断
${key}_${locale}是data的键,用as keyof T辅助类型检查,而泛型约束已经保证了该键要么存在,要么回退键一定存在。
内容的提问来源于stack exchange,提问作者Duncan
相关产品推荐
相关产品推荐

