我想将
i18next
翻译键声明为对象中的属性值,并将其键入为 Record<string, SomeType>
,使其仅接受有效 i18next
翻译键的值(仅叶子,因为我不想要它)接受具有嵌套键的部分的键,以便当我将键传递给 t()
时结果始终是一个字符串)。
我有这个代码(使用
i18next
22.4 和 react-i18next
12.2)
import { useTranslation } from 'react-i18next';
import type { TFuncKey } from 'i18next';
// A map of paths to translation keys
// I want TS to complain here if I try to use a string that
// doesn't match a translation key matching a string.
// This below works otherwise but `TFuncKey` is a bit too loose type as
// it also accepts e.g. 'Navigation` which results in an object, not a string.
const pageTitles: Record<string, TFuncKey> = {
'/': 'Navigation.home', // note: plain string values here, not calling `t()`
'/about': 'Navigation.about',
'/other': 'Navigation.other',
};
function useTitle(path: string): string {
const { t } = useTranslation();
return pageTitles[path] ? t(pageTitles[path]) : t('ErrorMessages.error');
// The previous line currently gives a TS error because t(pageTitles[path]) may
// return an object (not matching the return type of string in this method)
}
我可以使用
t(pageTitles[path]) as string
解决该错误,但它可能会在运行时中断,因为 TFuncKey
类型有点太松散,我可能会意外传递像 ''Navigation''
这样的值,传递时不会产生字符串到t()
。
如果我像这样内联地图对象,那么代码将按预期工作:
function useTitle(path: string): string {
const { t } = useTranslation();
return {
'/': t('Navigation.home'), // note: calling `t()` here directly
'/about': t('Navigation.about'),
'/other': t('Navigation.other'),
}[path] ?? t('ErrorMessages.error');
}
但我想重构要在其他地方(在此 React 钩子之外)声明的映射,我不能使用
useTranslation()
,因为我的实际代码比此处的示例更复杂(并且有更多路线)。因此,如果可能的话,如果可以修复打字以便 TS 满意的话,我希望它更像第一个示例。
我不确定是否可以使用
TFuncKey
的泛型或 i18next
中的其他类型来解决我的问题。
使页面标题常量。
const pageTitles = {
'/': 'Navigation.home',
'/about': 'Navigation.about',
'/other': 'Navigation.other',
} as const;