👑

TypeScript応用

に公開

はじめに

実務で TypeScript を使用していますが、なんとなく基礎の型の使い方しかできなかったので、応用的な使い方の型についてまとめます。

対象読者

TypeScript を実務で使い始めたが、なんとなくで使っている人

前提知識・用語

一旦読み飛ばして、わからなかったときにここに戻って読んでみてください。

リテラル型:
プリミティブ型の特定の値だけを代入可能にする型。

const isTrue: true = true;
const num: 123 = 123;
const str: "foo" = "foo";

型アノテーション:
変数宣言のときに変数名の後ろに: Tと書くこと。

ユーティリティ型:
型から別の型を作ってくれる型のこと。Readonly<T>Required<T>はその一種。これらの定義に後述する応用的な型の使い方が使われているというイメージ。

演算子key of:
オブジェクトの型からプロパティー名(=キー名)をユニオン型で返す型演算子。

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

type PersonKey = key of Person;
// PersonKeyは 'name' | 'number'

応用

では、ここから型の応用的な使い方についてまとめます。

型アサーション

TypeScript コンパイラが推論する型情報をas xxとすることで上書きすること。

const value: string | number = "this is a string";

// valueをリテラル型としたときの文字数が知りたいとき
const strLength = (value as string).length;
// asだけでなく以下のアングルブラケット構文と呼ばれる書き方もある
const strLength = (<string>value).length;

アングルブラケット構文は JSX と見分けがつきにくいため as 構文を使うことが多い。

const アサーション

変数宣言するとき、末尾にas constをつけると変数をreadonlyにした上で、リテラル型にしてくれる。

const array = [1, 2, 3];
// const array: number[]とコンパイラは推論するが、

const array = [1, 2, 3] as const;
// const array: readonly [1, 2, 3]とすることができる。

演算子satisfies

satisfies Tはその値が型を満たすかどうかを検証する演算子である。

type Country = {
  name: string;
  population: number;
  region: string;
};

type Japan = {
  name: "japan";
  population: 13000
  region: 'asia'
} satisfies Country;

型アノテーション : Tと異なる点は、Tにユニオン型が入っても、実際の値に基づいて型を絞り込んでくれる点です。

const array1: (string | number)[] = [1, 2, 3];     
// const array1: (string | number)[]
const array2 = [1, 2, 3] satisfies (string | number)[];
// const array2: number[]まで絞り込んでくれる

Mapped Types

ある型のプロパティを、ループすることで、変換したり、再生成する書き方。

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

使用用途

上の Person という型をすべてオプショナルにしたいとき、Mapped Types の書き方を使うと以下のように書けます。

type OptionalPerson = {
  [K in keyof Person]?: Person[K];
};

// 上記は以下と同義
type OptionalPerson = {
  name?: string;
  age?: number;
};
  • key of Person'name'| 'age'と同義で、キーを集めたリストのようなもの
  • [K in keyof Person] は「キーをひとつずつ取り出してループする」イメージ
  • Person[K]はそのキーに対応する型

Conditional Types

型に対して if 文のように条件分岐できる型のこと。以下に基本形を示します。

T extends U ? X : Y
type IsNumber<T> = T extends number ? true : false;

type T1 = IsNumber<300>; // type T1 = true
type T2 = IsNumber<"テスト">; // type T1 = false

Distributive Conditional Types(ユニオンの分配)

type Distribute<T> = T extends any ? T[] : never;

type Union = number | string | boolean;
type DistributedUnion = Distribute<Union>;
// この型は number[] | string[] | boolean[]

infer

Conditional Types の中で使われるキーワードで、「型から別の型を推論(infer)する」ための仕組み。

type Unwrap<T> = T extends Promise<infer U> ? U : T;

type A = Unwrap<Promise<string>> // Aはstring

参考文献

https://qiita.com/u83unlimited/items/b283264bcee3c643b2b9

Discussion