You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript实现指向Translation类型的点分隔路径强类型校验

TypeScript 翻译路径强类型校验实现方案

报错原因

你遇到的类型报错是 TypeScript 泛型约束的前置校验逻辑导致的:即使你已经在条件分支中写了T[TKey] extends Translations的判断,TS 在校验递归泛型参数时不会提前带入条件分支的判断结果,依然会用T[TKey]的原始类型Translation | Translations | undefined去匹配Translations约束,因此触发报错。

最优实现方案

我们可以换个思路:直接从翻译结构中生成所有合法的、指向Translation类型的点分隔路径联合类型,再用这个联合类型约束入参,逻辑更简洁,也能避开递归参数校验问题:

type Language = "pl" | "en";
type Translation = { [lang in Language]: string };
type Translations = { [key: string]: Translation | Translations | undefined };

// 核心:生成T下所有指向Translation类型的点分隔路径联合
type PathsToTranslation<T extends Translations> = {
  // 遍历所有字符串类型的key
  [K in keyof T & string]: T[K] extends Translation
    // 如果当前key对应的值就是Translation,直接返回当前key作为合法路径
    ? K
    // 如果当前key对应的值还是Translations嵌套结构,递归拼接子路径
    : T[K] extends Translations
      ? `${K}.${PathsToTranslation<T[K]>}`
      // 过滤undefined和其他不合法值
      : never
}[keyof T & string]

// 函数实现
function printTranslationByDeepKey<T extends Translations, K extends PathsToTranslation<T>>(
  t: T,
  k: K
) {
  // 运行时按路径取值,类型已经保证取值结果为Translation
  const translation = k.split('.').reduce((current, key) => current?.[key], t) as Translation
  console.log(translation)
}

测试效果

使用你提供的示例翻译结构测试,完全符合预期校验规则:

const translations = {
  hello: { pl: "Dzieńdobry", en: "Hello" },
  bool: {
    yes: { pl: "Tak", en: "Yes" },
    no: { pl: "Nie", en: "No" },
  },
} as const;

// 合法调用,无报错
printTranslationByDeepKey(translations, "hello")
printTranslationByDeepKey(translations, "bool.yes")
printTranslationByDeepKey(translations, "bool.no")

// 非法调用,均触发类型报错
printTranslationByDeepKey(translations, "bool") // 指向嵌套结构,不合法
printTranslationByDeepKey(translations, "missing") // 不存在的路径
printTranslationByDeepKey(translations, "bool.foo") // 不存在的子路径
printTranslationByDeepKey(translations, "hello.pl") // 指向Translation内部字段,不合法

原有写法的修复方案

如果你要保留原有传入K做匹配的写法,只需要用Extract工具类型提取T[TKey]中符合Translations约束的部分,即可解决泛型参数校验报错:

type DeepKeyToTranslation<T extends Translations, K extends string> = 
K extends keyof T
  ? T[K] extends Translation
    ? K
    : never
  : K extends `${infer TKey}.${infer Rest}`
    ? TKey extends keyof T
      ? T[TKey] extends Translations
        // 用Extract提取合法的Translations类型传入递归
        ? Rest extends DeepKeyToTranslation<Extract<T[TKey], Translations>, Rest>
          ? K
          : never
        : never
      : never
    : never

内容的提问来源于stack exchange,提问作者Chris Pfohl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 07:36:05