如何使用TypeScript输入检查i18n词典?

问题描述 投票:0回答:1

是否有可能在react-i18next词典中键入检查现有键?这样,如果密钥不存在,TS会在编译期间警告您。

示例。

假设我们有这本字典:

{
  "footer": {
    "copyright": "Some copyrights"
  },

  "header": {
    "logo": "Logo",
    "link": "Link",
  },
}

如果我提供了不存在的密钥,TS应该爆炸:

const { t } = useTranslation();

<span> { t('footer.copyright') } </span> // this is OK, because footer.copyright exists
<span> { t('footer.logo') } </span> // TS BOOM!! there is no footer.logo in dictionary

此技术的专有名称是什么?我非常确定我不是唯一一个要求这种行为的人。

是否在react-i18next中开箱即用?react-i18next中是否有API以某种方式扩展该库以启用它?我想避免创建包装器函数。

typescript i18next react-i18next
1个回答
0
投票

虽然我同意强类型键在i18next中将非常有帮助,但有两个原因无法实现:

1。)TypeScript无法像dynamic/computed string expressions那样评估'footer.copyright',因此footercopyright可以被识别为翻译对象层次结构中的关键部分。

2。)响应i18nextuseTranslationAPI与字符串一起使用(比较类型herehere),并且不对您定义的字典/译文施加类型依赖性。相反,t函数包含通用类型参数,如果不手动指定,则默认为string或类似的扩展类型。


[知道您不想使用包装器,这只是我前段时间汇总的一个示例示例,它使用了Rest参数/元组。

键入t功能:

type Dictionary = string | DictionaryObject;
type DictionaryObject = { [K: string]: Dictionary };

interface TypedTFunction<D extends Dictionary> {
    <K extends keyof D>(args: K): D[K];
    <K extends keyof D, K1 extends keyof D[K]>(...args: [K, K1]): D[K][K1];
    <K extends keyof D, K1 extends keyof D[K], K2 extends keyof D[K][K1]>(
        ...args: [K, K1, K2]
    ): D[K][K1][K2];
    // ... up to a reasonable key parameters length of your choice ...
}

键入useTranslation挂钩:

import { useTranslation } from 'react-i18next';

type MyTranslations = {/* your concrete type*/}
// e.g. via const dict = {...}; export type MyTranslations = typeof dict

// hook you import in other modules instead of i18next useTranslation
export function useTypedTranslation(): { t: TypedTFunction<typeof dict> } {
  const { t } = useTranslation();
  // implementation goes here. Here join keys by dot (depends on your options)
  return { t(...keys: string[]) { return keys.join(".") } }  
}

在其他模块中导入useTypedTranslation

import { useTypedTranslation } from "./useTypedTranslation"

const App = () => {
  const { t } = useTypedTranslation()
  return <div>{t("footer", "copyright")}</div>
}

测试:

const res1 = t("footer"); // const res1: { "copyright": string;}
const res2 = t("footer", "copyright"); // const res2: string
const res3 = t("footer", "copyright", "lala"); // error, OK
const res4 = t("lala"); // error, OK
const res5 = t("footer", "lala"); // error, OK

Playground

您可能可以通过infer自动而不是上面的多个重载签名来recursive types这些类型。但是in this case TS小组does not recommend them for production,所以我在这里介绍后者。

希望,会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.