Programmingフルスタック開発者

TypeScriptにおけるExcludeはどのように機能し、ユニオン型の操作に使用する場合の注意点は何ですか?

Hintsage AIアシスタントで面接を突破

回答。

Exclude<T, U>はTypeScriptにおいて、ユニオン型から特定の値を除外するためのユーティリティ型です。

背景

当初TypeScriptには、型を他の型から引くための便利な方法がありませんでした。ジェネリックなAPIを作成したり、リファクタリングを行う際には、しばしば「残りの」型、つまり禁止された値を除いたすべての型を取得する必要がありました。手動でユニオンを操作する代わりに、いくつかの類似のインターフェースを維持する必要がありました。

問題

例えば、型'A | B | C'があるが、Bを除いた型を取得する必要があることがよくあります。これは、関数の複雑な入力パラメータを構築したり、許可された値をフィルタリングしたり、動的に型を生成する際にしばしば求められます。

解決策

Excludeはこの問題を解決します。その簡略化されたシグネチャは次のとおりです:

type Exclude<T, U> = T extends U ? never : T;

これは、TからUのすべてのメンバーを除外した型を返します。

例:

type Status = 'draft' | 'published' | 'removed'; type UserVisibleStatus = Exclude<Status, 'removed'>; const visible: UserVisibleStatus = 'draft'; // OK

主な特徴:

  • ユニオンから部分を「引き算」することで動的型を形成できます。
  • リファクタリングを簡素化します — 基本型を変更すると、すべての派生型が自動的に更新されます。
  • スイッチケースやオブジェクトのキーをフィルタリングするために使用できます。

トリックな質問。

Excludeを通常の型に使用できますか?ユニオンではなく?

もしTがユニオン型でなく、Uに含まれる場合でもExcludeは機能しますが、結果はneverまたはTとなり、必ずしも直感的ではありません。

Exclude<'a', 'a'> // 結果: never Exclude<'a', 'b'> // 結果: 'a'

Excludeはオブジェクトの構造内の型のすべての出現を削除しますか?

いいえ、Excludeは型のネストされたフィールドを再帰的に通過せず、ユニオンの上位レベルのみで除外を行います。

Excludeはインターフェースやオブジェクト型とどのように機能しますか?

それは型全体を比較し、個々のプロパティではありません。したがって、いくつかのインターフェースのユニオンからExcludeすると、Uと完全に一致するもののみが削除されます。

interface A { x: number }; interface B { y: string }; // Exclude<A|B, B>はAを返します (Bは完全に一致)

型に関するエラーとアンチパターン

  • ネストされたまたは部分的一致を持つ型にExcludeを適用しようとすること
  • ユニオンではなくインターフェースのプロパティを「削除」するための使用
  • 型が完全に一致した場合にnever型を得る可能性を無視すること

実生活の例

ネガティブケース

Exclude<UserRoles, 'admin'>を使用してユーザーの役割を検証しましたが、Excludeはネストされた構造に適用されないため、'admin:sub'という権限が除外されませんでした。

利点:

  • 役割の型の簡素な形成。

欠点:

  • ネストされたまたは類似した型に関する直感的ではない振る舞い; 重要な役割が見逃されました。

ポジティブケース

Exclude<Action, 'delete'>を使用して公開APIを制限することで、危険な操作を除外します。

利点:

  • 型の安全性において、禁止された操作を呼び出すことができません。

欠点:

  • 基本型の最新のリストを維持する必要があります。