Open5

TypeScript

じゃーにゃりすとじゃーにゃりすと

型の再利用

型の再利用とは既存の型を再度利用して、新たな型を生み出すこと

typeof型演算子

変数から型を抽出する型演算子で、変数や式の型をそのまま別の変数の型として使用できる

let num: number = 42;
let str: typeof num;

str = "Hello"; // エラー: strの型はnumberでなければならない
str = 100;     // エラー: strの型はnumberでなければならない
str = num;     // 有効: strの型はnumberとなり、numもnumber型なので代入できる

変数や式の型が変更された場合に、手動で型を修正する手間を省くのに役立つ

keyof型演算子

オブジェクトの型からプロパティ名を型として返す型演算子
2つ以上のキー(プロパティ)があるオブジェクトの型にkeyofを使った場合は、すべてのプロパティ名がユニオン型で返される

type Person = {
  name: string;
  age: number;
  address: string;
};

type PersonKeys = keyof Person;
// PersonKeysの型は "name" | "age" | "address" となる

インデックス型にkeyofを使うと、インデックスキーの型が返る
キーがstringのインデックス型は、stringではなくstring | numberが返ります

type MapLike = { [K: string]: any };
type MapKeys = keyof MapLike;
// MapKeysの型は "string" | "number"  となる

Mapped Typesにkeyofを使うと、そのキーの型が返る

type MapLike = { [K in "x" | "y" | "z"]: any };
type MapKeys = keyof MapLike;
// MapKeysの型は "x" | "y" | "z"  となる

プロパティを持たないオブジェクトの型にkeyofを使うとnever型が返る

type What = keyof {};
// Whatの型は "never" となる

any型にkeyofを使うとstring | number | symbol型が返ります。

type AnyKeys = keyof any;
// AnyKeysの型は "string" | "number" | "symbol" となる
じゃーにゃりすとじゃーにゃりすと

ユーティリティ型

ユーティリティ型は型から別の型を導き出してくれる型で、既存の型を組み合わせたり変換したりすることができる

Required<T>

全プロパティを必須にする

type Person {
  name?: string;
  age: number;
}

type RequiredPerson = Require<Person>;
// RequiredPersonの型は { name: string; age: number; } となる

Readonly<T>

全プロパティを読み取り専用にする

type Person {
  name: string;
  age: number;
}

type ReadonlyPerson = Readonly<Person>;
// ReadonlyPersonの型は { readonly name: string; readonly age: number; } となる

Partial<T>

全プロパティをオプショナルにする

type Person {
  name: string;
  age: number;
}

type PartialPerson = Partial<Person>;
// PartialPersonの型は { name?: string; age?: number; } となる

Record<Keys, Type>

キー・バリューからオブジェクト型を作る

type Colors = "red" | "blue" | "green";
type ColorCodes = Record<Colors, string>;

// ColorCodesの型は { red: string; blue: string; green: string; } となる

Pick<T, Keys>

任意のプロパティだけを持つオブジェクト型を作る

type Person {
  name: string;
  age: number;
  address: string;
}

type PersonName = Pick<Person, "name">;
// PersonNameの型は { name: string; } となる

Omit<T, Keys>

任意のプロパティを除いたオブジェクト型を作る

type Person {
  name: string;
  age: number;
  address: string;
}

type PersonWithoutAge = Omit<Person, "age">;
// PersonWithoutAgeの型は { name: string; address: string; } となる

Exclude<T, U>

任意の方を除外する

type AllColors = 'red' | 'blue' | 'green';
type PrimaryColors = 'red' | 'blue';

type SecondaryColors = Exclude<AllColors, PrimaryColors>;
// SecondaryColorsの型は 'green' となる

Extract<T, U>

任意の型だけを抽出する

type AllColors = 'red' | 'blue' | 'green';
type PrimaryColors = 'red' | 'blue';

type CommonColors = Extract<AllColors, PrimaryColors>;
// CommonColorsの型は 'red' | 'blue' となる

Omit<T, Keys>とExclude<T, U>の違い(どちらも除外)

  • Omitはオブジェクト型に対して使用され、プロパティ名を指定して除外
  • Excludeはユニオン型や合併型に対して使用され、指定した型をユニオンから除外

Pick<T, Keys>とExtract<T, U>の違い(どちらも抽出)

  • Pickはオブジェクト型に対して使用され、プロパティ名を指定して抽出
  • Extractはユニオン型や合併型に対して使用され、特定の型(型の一部)を抽出する
じゃーにゃりすとじゃーにゃりすと

Mapped Types(マップ型)

Mapped Typesは主にオブジェクト型に対して使用され、各プロパティの型を変更したり、新しいプロパティを追加したりする

type NewType = {
  [Key in ExistingType]: NewValueType;
};

Partial<T>やReadonly<T>はMapped Typesの一種

Mapped Typesには追加のプロパティが書けない

追加のプロパティがある場合は、その部分をオブジェクトの型として定義し、Mapped Typesとインターセクション型を成す必要がある

type KeyValuesAndName = {
  [K in string]: string;
} & {
  name: string; // 追加のプロパティ
};
じゃーにゃりすとじゃーにゃりすと

インデックスアクセス型

オブジェクトの型から特定のプロパティの型や配列要素の型を参照することができる

type Person {
  name: string;
  age: number;
  address: {
    city: string;
    postalCode: string;
  };
}

type PersonName = Person['name'];
// PersonNameの型は string となる

type PersonCity = Person['address']['city'];
// PersonCityの型は string となる
じゃーにゃりすとじゃーにゃりすと

ジェネリクス (generics)

ジェネリクスは、プログラムが実行される時点では具体的な型を指定せず、後から利用時に型を指定できる機能である

ジェネリクスの基本的な構文

function identity<T>(arg: T): T {
  return arg;
}

<T>の部分がジェネリクス

ジェネリクスのを使用したクラスの例

class Box<T> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  getValue(): T {
    return this.value;
  }
}

// 利用例
const stringBox = new Box<string>("Hello");
const numberBox = new Box<number>(42);

console.log(stringBox.getValue()); // "Hello"
console.log(numberBox.getValue()); // 42

利用時に型を指定することで、ジェネリクス関数は様々な型に対応できる