是否有可能在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以某种方式扩展该库以启用它?我想避免创建包装器函数。
虽然我同意强类型键在i18next中将非常有帮助,但有两个原因无法实现:
1。)TypeScript无法像dynamic/computed string expressions那样评估'footer.copyright'
,因此footer
和copyright
可以被识别为翻译对象层次结构中的关键部分。
2。)响应i18nextuseTranslation
API与字符串一起使用(比较类型here和here),并且不对您定义的字典/译文施加类型依赖性。相反,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
您可能可以通过infer自动而不是上面的多个重载签名来recursive types这些类型。但是in this case TS小组does not recommend them for production,所以我在这里介绍后者。
希望,会有所帮助。