TypeScript の条件型に関する詳細な読書と実践記録

TypeScript の条件型に関する詳細な読書と実践記録

ほとんどのプログラムでは、入力に基づいて決定を下す必要があります。 TypeScript も例外ではなく、条件型を使用して入力型と出力型の関係を記述できます。

条件判断に使用される

条件判断を表現するために extends を使用する場合、次のルールをまとめることができます。

extends の両側の型が同じである場合、次の例に示すように、extends は意味的には === として理解できます。

type result1 = 'a' extends 'abc' ? true : false // false
type result2 = 123 extends 1 ? true : false // false

extends の右側の型に extends の左側の型が含まれている場合 (つまり、狭い型が広い型を拡張している場合)、結果は true になります。それ以外の場合は false になります。次の例を参照してください。

type result3 = string extends string | number ? true : false // true

オブジェクトに extends を適用すると、オブジェクトに指定されるキーが増えるほど、その型定義の範囲は狭くなります。次の例を参照してください。

type result4 = { a: true, b: false } extends { a: true } ? true : false // true

ジェネリック型での条件型の使用

次のデモ型定義を検討してください。

型 Demo<T, U> = T は U を拡張しますか? 決して: T

条件判断で使用される extends と組み合わせると、 'a' | 'b' | 'c' extends 'a' は false であることがわかります。したがって、 Demo<'a' | 'b' | 'c', 'a'> の結果は 'a' | 'b' | 'c'? になります。
公式ウェブサイトを確認してください。そこには次のように記載されています。

条件付き型がジェネリック型に作用する場合、ユニオン型が指定されると分散型になります。

つまり、条件型がジェネリック型に作用する場合、ユニオン型が分割されて使用されます。つまり、Demo<'a' | 'b' | 'c', 'a'> は、'a' extends 'a'、'b' extends 'a'、'c' extends 'a' に分割されます。疑似コードでは次のようになります:

関数Demo(T, U) {
  T.map(val => { を返す
    if (val !== U) valを返す
    'never' を返す
  })
}

Demo(['a', 'b', 'c'], 'a') // ['never', 'b', 'c']

さらに、never 型の定義によれば、never 型はすべての型に代入可能ですが、never にはどの型も代入できません (never 自身を除く)。つまり、 | 'b' | 'c' は 'b' | 'c' と同等ではありません。

したがって、Demo<'a' | 'b' | 'c', 'a'> の結果は 'a' | 'b' | 'c' ではなく 'b' | 'c' になります。

ツールタイプ

注意深い読者は、Demo 型の宣言プロセスが実際には TypeScript によって公式に提供されるツール型の Exclude<Type, ExcludedUnion> の実装原理であり、Type 型から共用体型 ExcludedUnion を除外するために使用されることに気付いたかもしれません。

type T = Demo<'a' | 'b' | 'c', 'a'> // T: 'b' | 'c'

デモ型定義に基づいて、公式ツール型にOmit<Type, Keys>をさらに実装することができます。これは、オブジェクトTypeを削除するために使用されます。
キー タイプを満たす属性値。

型 Omit<Type, Keys> = {
  [P in Demo<keyof Type, Keys>]: Type<P>
}

インターフェースTodo {
  タイトル: 文字列;
  説明: 文字列;
  完了: ブール値;
}

type T = Omit<Todo, 'description'> // T: { title: string; complete: boolean }

脱出ポッド

Demo<'a' | 'b' | 'c', 'a'> の結果を 'a' | 'b' | 'c' にしたい場合、それは可能ですか? 公式 Web サイトの説明によると:

通常、分散性が望ましい動作です。その動作を回避するには、extends キーワードの両側を角括弧で囲みます。

ジェネリック内のすべての型を反復処理したくない場合は、ジェネリックを角括弧で囲んで、ジェネリックを使用する部分全体を示すことができます。
型 Demo<T, U> = [T] は [U] を拡張しますか? 決して: T

型 Demo<T, U> = [T] は [U] を拡張しますか? 決して: T

// 結果の型は 'a' | 'b' | 'c' です
タイプ結果 = Demo<'a' | 'b' | 'c', 'a'>

矢印関数で条件型を使用する

矢印関数で三項式を使用する場合、括弧で囲まないと、左から右に読む習慣により関数のコンテンツ領域がわかりにくくなります。たとえば、次のコードでは、 x は関数型ですか、それともブール型ですか?

// 意図が明確ではありません。
var x = a => 1 ? 真: 偽

eslint ルール no-confusing-arrow では、以下が推奨されます。

var x = a => (1 ? 真: 偽)

TypeScript の型定義では、矢印関数で extends が使用されている場合も同様です。左から右に読む習慣があるため、型コードの実行順序について読者が混乱する可能性があります。

型 Curry<P extends any[], R> =
  (引数: Head<P>) => HasTail<P> は true を拡張しますか? Curry<Tail<P>, R> : R

したがって、矢印関数で extends を使用する場合は括弧を追加することをお勧めします。これはコードレビューに非常に役立ちます。

型 Curry<P extends any[], R> =
  (引数: Head<P>) => (HasTail<P> は true を拡張しますか? Curry<Tail<P>, R> : R)

型推論による条件型の使用

TypeScript では、型推論構文は通常、extends と組み合わせて使用​​されます。型を自動的に推論するという目的を達成するために使用します。たとえば、関数 Type の戻り値の型を返すために使用されるツール タイプ ReturnType<Type> を実装するために使用できます。
type ReturnType<T extends Function> = T extends (...args: any) => infer U ? U : never

type ReturnType<T extends Function> = T extends (...args: any) => infer U ? U : never

MyReturnType<() => 文字列> // 文字列
MyReturnType<() => Promise<boolean> // Promise<boolean>

extends と型推論を組み合わせると、配列関連の Pop<T>、Shift<T>、および Reverse<T> ツール型も実装できます。

ポップ<T>:

type Pop<T extends any[]> = T extends [...infer ExceptLast, any] ? ExceptLast : never

タイプ T = Pop<[3, 2, 1]> // T: [3, 2]

Shift<T>:

type Shift<T extends any[]> = T extends [infer _, ...infer O] ? O : なし

タイプ T = Shift<[3, 2, 1]> // T: [2, 1]

逆順<T>

型 Reverse<T> = T は [F を推論し、...Others を推論] を拡張します。
  ? [...逆<その他>, F]
  : []

type T = Reverse<['a', 'b']> // T: ['b', 'a']

条件型を使用して、2つの型が完全に等しいかどうかを判断します。

条件型を使用して、型 A と型 B が完全に等しいかどうかを判断することもできます。現在、コミュニティには 2 つの主な解決策があります。

解決策 1: 問題を参照してください。

エクスポート型Equal1<T, S> =
  [T]は[S]を拡張しますか?(
    [S] は [T] を拡張しますか? 真: 偽
  ) : 間違い

現時点でこのソリューションの唯一の欠点は、どのタイプも他のタイプと同等であると判断されることです。

type T = Equal1<{x:any}, {x:number}> // T: true

解決策 2: 問題を参照してください。

エクスポート型Equal2<X, Y> =
  (<T>() => TはXを拡張しますか? 1:2)は拡張します
  (<U>() => U は Y を拡張しますか? 1 : 2) ? 真: 偽

このソリューションの唯一の欠点は、交差タイプの処理にいくつかの欠陥があることです。

type T = Equal2<{x:1} & {y:2}, {x:1, y:2}> // 偽

型が等しいかどうかを判断する上記の 2 つの方法についてはさまざまな意見があり、著者は議論を刺激するためにいくつかのアイデアを提示しているだけです。

要約する

これで、TypeScript の条件型を集中的に読み、実践するこの記事は終了です。TypeScript の条件型に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • TypeScript 列挙の基本と例
  • Typescript+React でモバイルと PC でシンプルなドラッグ アンド ドロップ効果を実現
  • オブジェクトのプロパティを反復処理する際の TypeScript の問題

<<:  IDEA が MySQL データベースに接続できない問題の 6 つの解決策

>>:  LinuxにNginxをインストールする詳細な手順

推薦する

Linux システムが VMware にインストールされているかどうかを確認する方法

現在の Linux システムが VMware にインストールされているかどうかを確認する方法を教えて...

Vue ドラッグ アンド ドロップのシンプルな実装

この記事では、主に次のような Vue ドラッグ アンド ドロップの簡単な実装を紹介します。レンダリン...

CentOS7.x のアンインストールとインストール MySQL5.7 の操作手順とエンコード形式の変更方法

1. MySQL 5.7 のアンインストール1.1查看yum是否安裝過mysql CD yum li...

Vue のフィルターの適用シナリオの詳細な説明

filterは通常、特定の値をフィルターするために使用されます。たとえば、フィールドが空だが、フロン...

mysql5.7.14 解凍版インストールと設定方法 グラフィックチュートリアル (win10)

Win10はmysql5.7の解凍版をインストールします。参考までに、具体的な内容は次のとおりです...

nginx で http でアクセスする Web サイトを https に変更する方法

目次1. 背景2. 前提条件https:証明書システム: 3. 操作プロセス3.1 証明書の生成3....

Windows 8 での MySQL 5.6.15 のインストールと設定方法のグラフィック チュートリアル

MySQLは私がとても気に入っているデータベースです。今日はWindows 8システムでインストール...

Webフロントエンドのパフォーマンス最適化

ウェブフロントエンド最適化のベストプラクティス: コンテンツWebフロントエンド最適化のベストプラク...

Google Recaptcha 認証を使用した Vue 実装例

最近のプロジェクトでは、Google ロボット認証を使用する必要があります。これには VPN が必要...

主要ブラウザとそのカーネルの紹介

トライデント コア: IE、MaxThon、TT、The World、360、Sogou Brows...

1 行のコードでさまざまな IE 互換性の問題を解決します (IE6-IE10)

x-ua-compatible は、IE ブラウザがページを解析およびコンパイルするためのモデルを...

win2008 で mysql8.0.11 を mysql8.0.17 にアップグレードする詳細な手順

アップグレードの背景: MySQLの下位バージョンの脆弱性を解決するために、MySQLはMySQL ...

HTML における Div と table の違い (あらゆる側面から詳細に説明)

1: 速度と読み込み方法の違いdivとtableの違いは速度ではなく、読み込み方法です。速度はネット...

MySQL テーブル結合クエリでグループ化と重複排除を実装する例

目次ビジネスロジックデータテーブル構造クエリロジックSQL スクリプトスクリプトの説明ビジネスロジッ...

MySQL の CPU 負荷が高い問題のトラブルシューティング

MySQL による CPU 負荷の上昇今日の午後、MySQL によってサーバーの負荷が高くなる問題を...