知らないかもしれない実用的なTypeScriptのヒント

知らないかもしれない実用的なTypeScriptのヒント

序文

長い間Typescriptを使ってきましたが、まだ使いこなせていない気がします。 TypeScript の多くの機能が使用されていないため、以前に書いたコードは any でいっぱいになり、多くのバグが発生しやすくなり、TypeScript の真の「型」のパワーが発揮されません。この記事では、今後 TypeScript を使用する際に役立つ、TypeScript の使用に関するヒントをいくつかまとめています。

では、これ以上長々とせずに、すぐにコードを見てみましょう。

関数のオーバーロード

ユーザーパラメータを渡す場合はフラグを渡さないでください。パラパラメータを渡す場合はフラグを渡します。次のように記述できます:

インターフェース ユーザー {
  名前: 文字列;
  年齢: 番号;
}

定数ユーザー = {
  名前: 'ジャック',
  年齢: 123
};

クラス SomeClass {

  パブリックテスト(para: User): number;
  パブリックテスト(para: number, flag: boolean): number;

  パブリックテスト(para: ユーザー | 数値、フラグ?: ブール値): 数値 {
    // 特定の実装 return 1;
  }
}

const someClass = 新しい SomeClass();

// わかりました
someClass.test(ユーザー);
someClass.test(123, false);

// エラー
// someClass.test(123); 
// 'number' 型の引数は 'User' 型のパラメータに割り当てることができません。
// someClass.test(user, false);
// '{ name: string; age: number; }' 型の引数は 'number' 型のパラメータに割り当てることができません。

マッピングタイプ

マッピング タイプを理解する前に、keyof、never、typeof、in を理解する必要があります。

keyof: keyofはインターフェースのキーを取得します

インターフェースポイント{
    x: 数値;
    y: 数値;
}

// タイプキー = "x" | "y"
タイプ keys = keyof Point;

never: 決して存在しない値のタイプ

公式の説明:

never 型は決して発生しない値の型を表します。

// 例: 包括的なコンパイル時チェックを実行する type Foo = string | number;

関数 controlFlowAnalysisWithNever(foo: Foo) {
  if (typeof foo === "文字列") {
    // ここで foo は文字列型に絞り込まれます } else if (typeof foo === "number") {
    // ここで foo は number 型に絞り込まれます } else {
    // foo はここには決して存在しません
    const チェック: never = foo;
  }
}

対応する実装のない新しいユニオン型の追加を回避するには、 never を使用します。目的は、完全に型安全なコードを記述することです。

typeof: 値の型を取得する

定数a: 数値 = 3

// 次と同等: const b: number = 4
定数 b: 型 a = 4

in: オブジェクトにプロパティが存在するかどうかを確認します

インターフェースA {
  x: 数値;
}

インターフェースB {
  y: 文字列;
}

関数doStuff(q: A | B) {
  ('x'がqにある場合){
    // 質問: A
  } それ以外 {
    // 質問: B
  }
}

マッピング タイプとは、あるタイプを別のタイプにマッピングすることです。簡単に言うと、新しいタイプは古いタイプの各属性を同じ形式で変換します。

部分的、読み取り専用、Null 可能、必須

  • 各プロパティをオプションのプロパティに部分的に変換します
  • 読み取り専用各プロパティを読み取り専用プロパティに変換します
  • Nullableは古い型とnullの結合に変換されます
  • 必須は各属性を必須属性にします
型 Partial<T> = {
    [TのキーのP]?: T[P];
}

型 Readonly<T> = {
    読み取り専用[P in keyof T]: T[P];
}

Nullable<T>型 = { 
  [T のキーの P]: T[P] | null 
}

型 Required<T> = {
  [TのキーのP]-?: T[P]
}

インターフェース Person {
    名前: 文字列;
    年齢: 番号;
}

PersonPartial と入力します。
PersonReadonly = Readonly<Person> と入力します。
PersonNullable 型 = Nullable<Person>;

タイプ PersonPartial = {
    名前?: 文字列 | 未定義;
    年齢?: 数値 | 未定義;
}

タイプ PersonReadonly = {
    読み取り専用の名前: 文字列;
    読み取り専用 age: 数値;
}

タイプ PersonNullable = {
      名前: 文字列 | null;
      年齢: 数値 | null;
}

インターフェースProps{
  a?: 数値;
  b?: 文字列;
}

定数obj: Props = { a: 5 };

const obj2: 必須<Props> = { a: 5 };
// プロパティ 'b' はタイプ '{ a: number; }' では欠落していますが、タイプ 'Required<Props>' では必須です。

選択、記録

  • 選択すると、新しいタイプを指定するための属性セットが選択されます
  • レコードは、新しい型を指定するための属性のセットを作成します。これは、通常のオブジェクトオブジェクトを宣言するためによく使用されます。
型 Pick<T, K は keyof T> を拡張します = {
  [KのP]:T[P];
}

型 Record<K extends keyof any, T> = {
  [K 内の P]: T;
}

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

type TodoPreview = Pick<Todo, "title" | "completed">;

定数todo: TodoPreview = {
  タイトル: 「クリーンルーム」
  完了: 偽、
};

todo; // = const todo: TodoPreview


インターフェース PageInfo {
  タイトル: 文字列;
}

Page = "home" | "about" | "contact" と入力します。

const nav: レコード<ページ、ページ情報> = {
  について: { タイトル: "title1" },
  連絡先: { タイトル: "title2" },
  ホーム: { タイトル: "title3" },
};

nav.about; // = const nav: レコード

除外、省略

  • 除外は交差部分を削除し、残りの部分を返します。
  • 除外はキーと値のペアのオブジェクトの除外に適用され、その型に含まれるキーと値のペアを削除します。
型 Exclude<T, U> = T は U を拡張しますか? 決して: T
タイプ Omit = Pick<T, Exclude<keyof T, K>>

// 次と同等: type A = 'a'
タイプ A = 除外<'x' | 'a', 'x' | 'y' | 'z'>

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

type TodoPreview = Omit<Todo, "description">;

定数todo: TodoPreview = {
  タイトル: "a",
  完了: 偽、
};

戻り値の種類

戻り値の型を取得します。通常は関数です。

型 ReturnType<T extends (...args: any) => any>
  = T は (...args: any) を拡張します => R ? R : any を推論します。

関数 f1() を宣言します: { a: 数値; b: 文字列 };
型 T1 = ReturnType<typeof f1>;
// タイプ T1 = {
// a: 数値;
// b: 文字列;
// }

マッピング タイプは他にもたくさんあります。ユーティリティ タイプ リファレンスを参照してください。

型アサーション

型アサーションは、値の詳細な型を TypeScript に明示的に伝えるために使用されます。適切に使用することで作業負荷を軽減できます。

たとえば、変数には初期値がありませんが、その型情報はわかっています(バックエンドから返される場合があります)。型情報を正しく推測して正常に実行する方法はありますか?オンラインで推奨される方法の 1 つは、初期値を設定し、typeof を使用して型を取得することです (他の場所でも使用できます)。この問題を解決するには、型アサーションを使用することもできます。

インターフェース ユーザー { 
    名前: 文字列; 
    年齢: 番号; 
}

デフォルトクラス someClass をエクスポートします。 
    プライベートユーザー = {} をユーザーとして;
} 

列挙する

列挙型は数値型と文字列型に分かれており、数値列挙はフラグとして使用できます。

列挙型動物フラグ{
    なし = 0、 
    爪あり = 1 << 0, 
    カンフライ = 1 << 1、 
    HasClawsOrCanFly = HasClaws | CanFly 
}

インターフェース動物{ 
    フラグ: AnimalFlags; 
   [キー: 文字列]: 任意; 
}

関数 printAnimalAbilities(animal: Animal) { 
    var animalFlags = animal.flags; 
    動物フラグと動物フラグ.爪がある場合 
        console.log('動物には爪があります'); 
    } 
    動物フラグと動物フラグ.CanFly の場合 { 
        console.log('動物は飛べる'); 
    } 
    動物フラグ == 動物フラグ.None の場合 { 
        console.log('何もない'); 
    } 
}

var animal = { flags: AnimalFlags.None }; 
printAnimalAbilities(animal); // なし 
animal.flags |= AnimalFlags.HasClaws; 
printAnimalAbilities(animal); // 動物には爪がある 
animal.flags &= ~AnimalFlags.HasClaws; 
printAnimalAbilities(animal); // なし 
animal.flags |= AnimalFlags.HasClaws | AnimalFlags.CanFly; 
printAnimalAbilities(animal); // 動物には爪があり、動物は飛べます 

  • フラグを追加するには |= を使用します。
  • フラグをクリアするには &= と ~ を一緒に使用します。
  • | フラグを結合します。

これはあまり一般的には使用されないかもしれません。TypeScript のソース コードにも、型に関する同様のコードが見られます。

文字列型の列挙では定数を保持できます。

定数列挙型TODO_STATUS {
  TODO = 'TODO'、
  完了 = '完了'、
  行う = '行う'
}

関数 todos (ステータス: TODO_STATUS): Todo[];

やること(TODO_STATUS.TODO)

タプル

既知の数と型の要素の配列を表します。同じ型である必要はありません。

let x: [文字列, 数値];
x = ['こんにちは', 10]; 

複数のリクエストを行う場合は、以下を適用できます。

const requestList: any[] = [http.get<A>('http://some.1')]; // any[]型に設定 if (flag) { 
    リクエストリスト[1] = (http.get<B>('http://some.2')); 
} 
const [ { data: a }, response ] = [Response<A>, Response<B>?] として Promise.all(requestList) を待機します。

パラダイム

ジェネリックを定義した後、ジェネリックを使用する方法は 2 つあります。1 つはジェネリック型を渡す方法、もう 1 つは型推論を使用する方法です。

関数 fn<T>(arg: T): T; // ジェネリック関数を定義します。const fn1 = fn<string>('hello'); // 最初の方法は、ジェネリック型文字列を渡します。const fn2 = fn(1); // 2 番目の方法は、パラメータ arg によって渡された型 number から、ジェネリック T の型が number であると推論します。 

フラットな配列構造からツリー構造を構築する例:

// 変換前のデータ const arr = [ 
{ id: 1、親ID: 0、名前: 'test1'}, 
{ id: 2、親ID: 1、名前: 'test2'}, 
{ id: 3、親 ID: 0、名前: 'test3'} 
]; 
// 変換後 [{ id: 1, parentId: 0, name: 'test1', 
    子供リスト: [ { id: 2, 親ID: 1, 名前: 'test2', 子供リスト: [] } ] }, 
    { id: 3、親ID: 0、名前: 'test3'、子リスト: [] } 
]


インターフェースアイテム{ 
    id: 番号; 
    親ID: 数値; 
    名前: 文字列; 
}

// 渡されたオプションパラメータからchildrenKeyの型を取得し、それをTreeItemに渡します

インターフェースOptions<T extends string> { 
    子供のキー: T; 
} 
type TreeItem<T extends string> = Item & { [T のキー]: TreeItem<T>[] | [] }; 
関数 listToTree<T extends string = 'children'>(list: Item[], options: Options<T>): TreeItem<T>[] を宣言します。 
listToTree(arr, { childrenKey: 'childrenList' }).forEach(i => i.childrenList) 

推測する

extends 条件文で推論される型変数を表します。

型 ParamType<T> = T は (param: infer P) => any ? P : T を拡張します。 

つまり、T を (param: infer P) => any に割り当てることができる場合、結果は (param: infer P) => any 型のパラメーター P になり、それ以外の場合は T を返します。

インターフェース ユーザー { 
    名前: 文字列; 
    年齢: 番号; 
} 
型 Func = (user: User) => void 
type Param = ParamType<Func>; // Param = User 
type AA = ParamType<string>; // 文字列

例:

// [文字列, 数値] -> 文字列 | 数値
type ElementOf<T> = T は Array<infer E> を拡張します。E : never;

タイプTTuple = [文字列、数値];

type ToUnion = ElementOf<TTuple>; // 文字列 | 数値


// T1 | T2 -> T1 & T2
型 UnionToIntersection<U> = (U は any ? (k: U) => void : never) を拡張し ((k: infer I) => void) ? I : never;

type Result = UnionToIntersection<T1 | T2>; // T1 & T2

要約する

Typescript は型の制限に関して非常に強力です。記事数が限られているため、和集合型、交差型など他の型もあります。読者は自分で情報を確認できます。パラダイムとそのさまざまな組み合わせに初めて触れるときは、慣れていないと感じるかもしれません。その後、ゆっくりとプロジェクトに適用し、バグを最小限に抑えるようにします。

これで、Typescript の実用的なヒントに関するこの記事は終了です。Typescript のより関連性の高い実用的なヒントについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • TypeScript 開発のための 6 つの実用的なヒント
  • TypeScriptはリソースファイルを参照し、例外を処理するときに見つからないことを通知します。
  • 実用的な TypeScript ワンライナー 7 つを共有する

<<:  MySQL の on と where における左結合設定条件の使用法の違いの分析

>>:  mysql5.7 の新しい json フィールド タイプの使用例の分析

推薦する

v-html レンダリング コンポーネントの問題

以前 HTML を解析したことがあるので、今日は Vue ドラッグ アンド ドロップを使用して、Ku...

Linux でシステム ディスクを初期化した後にデータ ディスクを再マウントする方法

Linuxインスタンスでシステムディスクを初期化した後、データディスクを再マウントするLinux イ...

Linux システムで PATH 環境変数を設定する方法 (3 つの方法)

1. Windows システムでは、JDK のインストールなど、多くのソフトウェアのインストールで...

MySQL InnoDBストレージエンジンについて簡単に説明します

序文:ストレージ エンジンはデータベースの中核です。MySQL の場合、ストレージ エンジンはプラグ...

Vue で jsx 構文を正しく使用する方法

目次序文仮想DOM仮想DOMとは仮想DOMの利点レンダリング関数とは何ですか? jsx Vue3 で...

CSSでイメージマッピングを実装する方法

1. はじめにイメージマップを使用すると、画像の領域をホットスポットとして指定できます。この領域にマ...

Web スライスとは何ですか?

IE8 の新機能 Web スライス (Web スライス) Microsoft は 3 月 20 日...

Dockerコンテナとローカルマシン間でファイルを転送する方法

ホストとコンテナ間でファイルを転送するには、コンテナの完全な ID が必要です。取得方法は以下の通り...

セマンティック HTML 構造の利点は何ですか?

1つ: 1.セマンティック タグは単なる HTML であり、CSS にはセマンティクスはありません...

単一の Nginx IP アドレスに複数の SSL 証明書を設定する例

デフォルトでは、Nginx は IP アドレスごとに 1 つの SSL 証明書のみをサポートします。...

Windows 8.1 で MySQL5.7 のルート パスワードを忘れた場合の解決方法

【背景】最近勉強中に非常に恥ずかしいことに遭遇しました。MySQL のパスワードを忘れてしまい、My...

CSSマウスを画像の上に置いたときにマスクレイヤー効果を追加する実装

まず効果を見てみましょう: マウスを画像の上に移動すると、影の効果とテキスト/アイコンが追加されます...

linuxdeployqt を使用して Ubuntu で Qt プログラムをパッケージ化する問題を解決する

いくつかの Qt インターフェース プログラムを作成しましたが、Qt 環境がインストールされていない...

JS オブジェクト配列の重複排除のための 3 つの方法の例と比較

目次1. 重複排除前後のデータの比較2. 使い方1. フィルターとマップを使用する2. 削減を使用す...