reactjs 如何键入一个字符串,该字符串应该匹配一个字符串而不是一个嵌套对象的i18next转换键?

k5hmc34c  于 2023-08-04  发布在  React
关注(0)|答案(2)|浏览(83)

我想将i18next转换键声明为对象中的属性值,并以一种只接受有效i18next转换键值的方式将其键入为Record<string, SomeType>(只接受叶子,因为我不希望它接受有嵌套键的部分的键,这样当我将键传递给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()时,它不会产生字符串。
如果我像这样内联map对象,那么代码就可以正常工作:

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');
}


但是我想重构Map,让它在其他地方声明(在这个React钩子之外),因为我的代码比这里的示例要复杂一些(并且路由更多)。所以如果可能的话,我希望它更像第一个例子,如果有可能修复类型,以使TS满意。
我不确定是否可以使用TFuncKey的泛型或i18next的其他类型来解决我的问题。

osh3o9ms

osh3o9ms1#

只需升级到i18next 23.x即可解决此问题。
类型TFuncKey将需要替换为ParseKeys,如迁移指南中所述(类型已重命名)。
我最初使用的是i18next 22.4(和react-i18next 12.2),但升级到i18next 23.4(和react-i18next 13.0)后,上面的代码就像预期一样工作,因为如果试图使用'Navigation'作为pageTitles对象的值,它会抱怨。
这是由于i18next 23中重新设计的新类型和returnObjects选项,该选项似乎全局默认为false(也可以显式设置为每次调用t()的选项)。

lsmepo6l

lsmepo6l2#

make pageTitles const.

const pageTitles = {
  '/': 'Navigation.home',
  '/about': 'Navigation.about',
  '/other': 'Navigation.other',
} as const;

字符串

相关问题