Хотя я согласен, что ключи со строгой типизацией были бы очень полезны в i18next, есть две причины, почему это невозможно:
1.) У TypeScript нет способа оценить динамические / вычисляемые строковые выражения подобно 'footer.copyright'
, поэтому footer
и copyright
могут быть определены как ключевые части в иерархии объектов перевода.
2.) Реагирует i18next useTranslation
API работает со строками (сравнивают типы здесь и здесь ) и не применяет зависимости типа к вашему определенному словарю / переводу. Вместо этого функция 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
// import this hook in other modules instead of i18next useTranslation
export function useTypedTranslation(): { t: TypedTFunction<typeof dict> } {
const { t } = useTranslation();
// implementation goes here: join keys by dot (depends on your config)
// and delegate to lib t
return { t(...keys: string[]) { return t(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
Детская площадка
Возможно, вы могли бы вывод этих типов автоматически с рекурсивными типами вместо приведенных выше сигнатур множественной перегрузки. Но в этом случае команда TS не рекомендует их для производства , поэтому я представляю последнее здесь.
Надеюсь, это поможет.