翻訳キーの型付け
メッセージファイルから有効なキーのユニオンを導出します。
「翻訳キーの型付け」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。
型安全な翻訳キーを導出する
型安全な i18n の構成では、有効な翻訳キーの集合がmessages オブジェクトから導出されます。t("greetng") のようなタイプミスは、ランタイムで文字列が見つからないバグではなく、コンパイルエラーになります。
Messages オブジェクト
まず、メッセージのプレーンなオブジェクトを用意します。これは値とキーの型の両方に対する単一の信頼できる情報源になります。
const messages = {
greeting: "Hello",
farewell: "Goodbye",
cart: {
empty: "Your cart is empty",
checkout: "Proceed to checkout",
},
} as const;keyof によるトップレベルキー
フラットなオブジェクトでは、keyof typeof によってキーのユニオン型を取得できます。
type TopKeys = keyof typeof messages;
// "greeting" | "farewell" | "cart"ネストされた場合の問題
実際のメッセージカタログはネストされています。トップレベルのキーだけでなく、"cart.empty" のようなドット区切りのパスが必要です。オブジェクトを走査する再帰的な型が必要になります。
再帰的なパス型
条件型と mapped type を組み合わせると、ネストされたオブジェクトを再帰的にたどり、キーに接頭辞を付けることでドット区切りのパスを構築できます。接頭辞にはテンプレートリテラル型を使います。実際のコードではバッククォートで [backtick]${K}.${Paths<T[K]>}[backtick] と記述します。リストを見やすくするため、ここでは JoinPath(K, child) として示します。
type JoinPath<K extends string, Rest extends string> = K + "." + Rest;
// (Real TS uses a template literal type:
// the K dot Rest pattern delimited by backticks.)
type Paths<T> = {
[K in keyof T & string]: T[K] extends string
? K
: K | (T[K] extends object
? JoinPath<K, Paths<T[K]>>
: never);
}[keyof T & string];適用する
messages の型を Paths に渡すと、有効なドット区切りキーをすべて取得できます。
type MsgKey = Paths<typeof messages>;
// "greeting" | "farewell" | "cart" | "cart.empty" | "cart.checkout"リーフだけのキー
多くの場合、途中のオブジェクトを除外し、リーフのパス(実際の文字列)だけが必要です。文字列以外のノードをスキップするように再帰処理を調整します。K-dot-child の接頭辞にもテンプレートリテラル型を使います(実際のコードではバッククォートで囲みます)。ここでは JoinPath として示します。
type LeafPaths<T> = T extends string
? ""
: {
[K in keyof T & string]: T[K] extends string
? K
: JoinPath<K, LeafPaths<T[K]>>;
}[keyof T & string];
// "greeting" | "farewell" | "cart.empty" | "cart.checkout"型付き t 関数
導出したキーのユニオン型に翻訳関数のパラメーターを制約し、有効なキーだけがコンパイルを通るようにします。
declare function t(key: LeafPaths<typeof messages>): string;
t("cart.empty"); // ok
t("cart.missing"); // Error: not a valid key値の型を解決する
さらに、パスから値の型を推論することもできます。これは、メッセージに文字列以外のエントリがある場合に便利です。パスをインデックスとして使う条件型がドットをたどります。パスはテンプレートリテラルパターンで分割します。実際のコードでは、バッククォートを使って Head dot Rest の形と infer を記述します。ここではその分割を SplitHead/SplitRest と表します。
// Conceptually: split "cart.empty" into Head="cart", Rest="empty"
// using a template literal pattern with infer.
type ValueAt<T, P extends string> =
P extends SplitHead<infer Head, infer Rest>
? Head extends keyof T ? ValueAt<T[Head], Rest> : never
: P extends keyof T ? T[P] : never;as const が重要な理由
as const がないと、文字列値は string 型に拡大され、後で必要になるリテラル情報(たとえばプレースホルダーの抽出)を失います。カタログは必ず const として宣言してください。
重要な理由
カタログからキーを導出すると、メッセージの追加、名前変更、削除が、許可されるキー型に即座に反映されます。維持する中央の enum も、古くなった文字列定数も必要ありません。
理解度チェック
翻訳キーの型付けについて、理解度を確認しましょう。
まとめ
keyof と再帰的なテンプレートリテラルパス型を使い、messages オブジェクトから有効なキーのユニオン型を導出しました。リーフだけの派生型では途中のオブジェクトを除外でき、型付きの t は無効なキーを拒否します。また、as const によって型の仕組みに必要なリテラル情報が保持されます。
よくある質問
「翻訳キーの型付け」レッスンは無料ですか?
はい。「翻訳キーの型付け」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。
「翻訳キーの型付け」で何を学びますか?
メッセージファイルから有効なキーのユニオンを導出します。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
TypeScript Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「翻訳キーの型付け」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このTypeScript Academyレッスンでコードを書いて実行できますか?
はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 翻訳キーの型付け
- 補間の型安全性
- 型による複数形処理
- ロケール対応の型推論