TypeScript - 継承型

こんにちは、未来のTypeScript魔法使いたち!今日は、Conditional Typesの世界への興味深い旅に出かけます。プログラミングが初めての方でも心配しないでください。私はあなたの親切なガイドとして、ステップバイステップで進めていきます。このレッスンの終わりには、学んだことがどれほど多いかに驚くことでしょう!

TypeScript - Conditional Types

基本的な継承型

まずは基本から始めましょう。TypeScriptのConditional Typesは、コード内で決定を行うようなものです。アイスクリーム屋にいるとしまして、天気が暑いかどうかによってチョコレートとバニラのどちらを選ぶ決定を行う、そんな感じです。这正是 TypeScript 中的 Conditional Types 所做的事情!

以下に簡単な例を示します:

type IceCreamChoice = boolean extends true ? "Chocolate" : "Vanilla";

このコードでは、「boolean(trueまたはfalseを表す)がtrueにすることができる場合、Chocolateを選択;さもなければ、Vanillaを選択」と言っています。

でも、booleanは常にtrueにできるじゃないですか?では、もっと実用的にしてみましょう:

type WeatherChoice<T> = T extends "Hot" ? "Ice Cream" : "Hot Chocolate";

let summerChoice: WeatherChoice<"Hot"> = "Ice Cream";
let winterChoice: WeatherChoice<"Cold"> = "Hot Chocolate";

ここでは、WeatherChoiceという型を定義し、型パラメータTを受け取ります。Tが"Hot"を継承(または一致)する場合、"Ice Cream"を選択;さもなければ、"Hot Chocolate"を選択します。

ジェネリックな継承型

次に、レベルアップしましょう!ジェネリックな継承型は、型をより柔軟かつ再利用可能にします。アイスクリームメーカーが、何を入れるかによって異なるフレーバーを作れる超级 flexibleなものを考えたとすると、そんな感じです。

type IsArray<T> = T extends any[] ? true : false;

type CheckString = IsArray<string>;  // false
type CheckNumberArray = IsArray<number[]>;  // true

この例では、IsArrayは入力型Tが配列であるかどうかをチェックするジェネリック型です。配列の場合はtrueを返し、それ以外の場合はfalseを返します。

もっと複雑なものを試してみましょう:

type ElementType<T> = T extends (infer U)[] ? U : never;

type StringArrayElement = ElementType<string[]>;  // string
type NumberArrayElement = ElementType<number[]>;  // number
type NotArrayElement = ElementType<number>;  // never

ここでは、ElementTypeは配列の要素の型を抽出します。Tが配列の場合、要素型Uを推論し、それを返します。Tが配列でない場合、never(「これは決して起こるべきでない」という意味)を返します。

継承型の制約

時々、型にいくつかの制約を設けたいことがあります。これは、「野菜を食べ終わったらアイスクリームを食べる」と言うようなものです。TypeScriptでの動作を見てみましょう:

type NumberOperation<T extends number> = T extends 0 ? "Zero" : "Non-zero";

type ZeroCheck = NumberOperation<0>;  // "Zero"
type NonZeroCheck = NumberOperation<5>;  // "Non-zero"
type InvalidCheck = NumberOperation<"5">;  // エラー: Type '"5"' does not satisfy the constraint 'number'.

この例では、NumberOperationnumberを継承する型のみを受け入れます。それから、数が0かどうかをチェックします。

継承型内での推論

最後に、継承型内での推論についてお話ししましょう。これは、あなたの気分に基づいてどのフレーバーが欲しいかを把握できる超级 smartなアイスクリームメーカーのようなものです!

type Flatten<T> = T extends Array<infer U> ? U : T;

type FlattenedNumberArray = Flatten<number[]>;  // number
type FlattenedString = Flatten<string>;  // string

ここでは、FlattenTが配列かどうかをチェックします。配列の場合、要素型Uを推論し、それを返します。それ以外の場合、Tをそのまま返します。

もっと高度なものを試みましょう:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

function greet(name: string): string {
return `Hello, ${name}!`;
}

type GreetReturn = ReturnType<typeof greet>;  // string

この例では、ReturnTypeは関数の戻り型を推論します。Tが関数型の場合、戻り型Rを推論し、それを返します。

結論

おめでとうございます!TypeScriptのConditional Typesへの最初の一歩を踏み出しました。自転車に乗るのと同じで、最初は不安定に感じるかもしれませんが、練習を続ければすぐにスムーズに走れるようになるでしょう!

以下は、私たちがカバーした方法の簡単な参照表です:

メソッド 説明
基本的な継承型 条件に基づいて型の決定を行う
ジェネリックな継承型 柔軟で再利用可能な継承型を作成する
継承型の制約 入力型に制約を設ける
継承型内での推論 条件内で型を抽出し推論する

練習を続け、好奇心を持ち続けてください。それさえあれば、TypeScriptで素晴らしいことを創造するでしょう。未来のTypeScriptマスターたち、ハッピーコーディング!

Credits: Image by storyset