0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【逆引き】react-i18nextの型推論

Posted at

環境

i18next: v25.3.x
react-i18next: v15.6.x

はじめに

React + TypeScript + i18nextの構成で、JSONリソースから型情報を自動生成し、型推論を効かせるための方法をまとめました。
必要な情報が公式ドキュメントだけでは分からなかったり、GitHub、Stack Overflowにバラバラに載っていたりしたので、調べるのに少し苦労しました。

そこで、自分の備忘録も兼ねて、ここにまとめておこうと思います。
この記事は、やりたいことに対してすぐに答えが見つかる逆引き形式になっています。

やりたいこと

型推論を有効化

i18nextの型定義をTypeScriptに認識させ、JSONのキーを補完できるようにします。

i18next.d.ts
import "i18next";
import ja from "../i18n/ja/translation.json";

declare module "i18next" {
  interface CustomTypeOptions {
    defaultNS: "ja";
    resources: {
      ja: typeof ja;
    };
  }
}

参考:
https://zenn.dev/sjbworks/articles/80b623a0e31a1b
https://www.i18next.com/overview/typescript

keyの型

JSONリソースのkeyに該当する型についてです。

NG
import { useTranslation } from "react-i18next";

{
  // JSX内
  const { t } = useTranslation();
  const translate = (key: string): string => {
    return t(key);
    // Argument of type '[string]' is not assignable to parameter of type '[key: string | string[], options: TOptionsBase & $Dictionary & { defaultValue: string; }] | [key: string | string[], defaultValue: string, options?: (TOptionsBase & $Dictionary) | undefined] | [key: ...]'.
  }
}

OK
import type { ParseKeys } from "i18next";  // インポート
import { useTranslation } from "react-i18next";
{
  // JSX内
  const { t } = useTranslation();
  // i18nextが提供する型ParseKeysをキーに指定する
  const translate = (key: ParseKeys): string => {
    return t(key);
  }
}

参考:
https://github.com/i18next/react-i18next/issues/1530#issuecomment-1722288325

keyの型ガード関数

ParseKeys型を使うことで、keyの存在をチェックする型ガード関数を作ることができます。
この例では、keyが存在すれば変換後の文字列を返し、存在しなければ引数をそのまま返すようにしています。

NG
import { useTranslation } from "react-i18next";
{
  // JSX内
  const { t } = useTranslation();
  const getLabel = (key: string): string => {
    return t(key);
    // Argument of type '[string]' is not assignable to parameter of type '[key: "...'.
  }
}
OK
import type { ParseKeys } from 'i18next';  // インポート
import { useTranslation } from "react-i18next";
{
  // JSX内
  const { t, i18n } = useTranslation();
  // string型をParseKeys型に絞り込む型ガード関数
  const isParseKeys = (arg: string): arg is ParseKeys => i18n.exists(arg);
  // 実際にキーが存在するかチェックする
  const getLabel = (key: string): string => {
    if (isParseKeys(key)) {
      return t(key);
    } else {
      console.warn(`i18n key "${key}" does not exist.`);
      return key; // キーが見つからない場合は引数keyをそのまま返す
    }
  }
}

参考:
https://stackoverflow.com/a/72471339
https://www.i18next.com/overview/api#exists

t関数の型

JSXの中では、useTranslationフックを使うことでt関数を簡単に利用できますが、コンポーネントの外に切り出した関数などで利用したい場合もあります。
そういうケースで、t関数の型を明示的に指定する方法です。

import type { TFunction } from "i18next";  // インポート
// i18nextが提供する型TFunctionを引数に指定する
const mapOptions = (definition: Definition[], t: TFunction): Option[] => {
  return options.map(opt => ({
    label: t(opt.labelKey),
    value: opt.value,
  }));
}

参考:
https://stackoverflow.com/a/78266163

さいごに

今回は、react-i18nextにおける型推論の活用方法をまとめました。
この記事が、同じ課題を持つ誰かの助けになれば幸いです。
もし新しい情報や、より良い方法を見つけたら、この記事に随時追加していく予定です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?