Open1

Utility Typesについて

mymy

UtilityTypes

・便利な型のライブラリ集

関数の返り値の型が欲しい、オブジェクトのそれぞれのプロパティを read only にしたいなど

TypeScript標準で組み込まれているUtilityTypes

ReturnType

関数の返り値を指定する

const foo = (id: string, age: number) => {
  return 0;
};

type Return<T> = T extends (...args: any[]) => infer U ?

type Foo = Return<typeof foo>;
const foo = (id: string, age: number) => {
  return 0;
};

type Foo = ReturnType<typeof foo>;

Readonly

type User = {
  name: string;
  age: number | null;
  country?: "US" | "UK" | "JP";
};

type ReadonlyUser = Readonly<User>;

const user: ReadonlyUser = {
  name: "bob",
  age: 20,
};

user.age = 30;
type User = {
  name: string;
  age: number | null;
  country: "US" | "UK" | "JP";
};

type ReadonlyUser = Readonly<User>;

const user: ReadonlyUser = {
  name: "bob",
  age: 20,
};

user.age = 30;

Readonlyであることが確認できます。

Cannot assign to 'age' because it is a read-only property.ts(2540)

ReadonlyUser型は以下のようになります。

type ReadonlyUser = {
    readonly name: string;
    readonly age: number | null;
    readonly country?: "US" | "UK" | "JP" | undefined;
}

Partial

optiolanにすることができる

type User = {
  name: string;
  age: number | null;
  country?: "US" | "UK" | "JP";
};

type ReadonlyUser = Readonly<User>;

const user: User = {
  name: "bob",
};

ageが定義されていないのでエラーとなります。

Property 'age' is missing in type '{ name: string; }' but required in type 'User'.ts(2741)
type User = {
  name: string;
  age: number | null;
  country?: "US" | "UK" | "JP";
};

type PartialUser = Partial<User>;

const user: PartialUser = {
  name: "bob",
};

PartialUser型は以下のようになります。

type PartialUser = {
    name?: string | undefined;
    age?: number | null | undefined;
    country?: "US" | "UK" | "JP" | undefined;
}

Required

全てを必須にしたいとき

type User = {
  name: string;
  age: number | null;
  country?: "US" | "UK" | "JP";
};

type RequiredUser = Required<User>;

const user: RequiredUser = {
  name: "bob",
  age: 20,
};

countryが必須であるというエラーが出るようになります。

Property 'country' is missing in type '{ name: string; age: number; }' but required in type 'Required<User>'.ts(2741)

countryのoptionalが消えていることがわかります。

type RequiredUser = {
    name: string;
    age: number | null;
    country: "US" | "UK" | "JP";
}

Pick

オブジェクトがあった時に必要なプロパティを選んで新たらしいオブジェクト型を返す

ageを除いた型を生成したいとき

type User = {
  name: string;
  age: number | null;
  country?: "US" | "UK" | "JP";
};

// 第一引数に対象となる型、第二引数に欲しいプロパティ
type PickUser = Pick<User, "name" | "country">;

const user: PickUser = {
  name: "bob",
  age: 20,
  country: "JP",
};

ageなんてものはないというエラーが出るようになります。

Type '{ name: string; age: number; country: "JP"; }' is not assignable to type 'PickdUser'.
  Object literal may only specify known properties, and 'age' does not exist in type 'PickdUser'.ts(2322)

PickdUser型は以下となります。

type PickdUser = {
    name: string;
    country?: "US" | "UK" | "JP" | undefined;
}

Omit

Pickの反対
いらないプロパティを排除して新しいオブジェクトを生成する

type User = {
  name: string;
  age: number | null;
  country?: "US" | "UK" | "JP";
};

// 第一引数に対象となる型、第二引数に排除したいプロパティ
type OmitUser = Omit<User, "age">;

const user: OmitUser = {
  name: "bob",
  age: 20,
  country: "JP",
};

OmitUser型は以下となります。

type OmitUser = {
    name: string;
    country?: "US" | "UK" | "JP" | undefined;
}

Extract

第一型引数と第二型引数を比較して互換性のある型だけを残して新しい型を生成する

// ①
type Foo = Extract<string | number, string>;

// ②stringのリテラル型
type Foo = Extract<"hello" | number, string>;

// ③第二引数にもユニオン型を使用
type Foo = Extract<"hello" | number, string | number>;

// ④numberのリテラル型
type Foo = Extract<"hello" | 0, string | number>;

// ⑤互換性のないものを指定
type Foo = Extract<"hello" | 0, boolean>;

Foo型は以下のように定義できています。

// ①
type Foo = string
// ②stringのリテラル型
type Foo = "hello"
// ③第二引数にもユニオン型を使用
type Foo = number | "hello"
// ④numberのリテラル型
type Foo = 0 | "hello"
// ⑤互換性のないものを指定
type Foo = never

※Pickはオブジェクト型から必要なプロパティを抽出するもの

Exclude

Extractの反対で第一型引数と第二型引数の中で互換性のないものだけを抽出したもの

// ①
type Foo = Exclude<string | number, string>;
// ②
type Foo = Exclude<string | number | boolean, string>;
// ③
type Foo = Exclude<string | number | boolean, string | number>;
// ④
type Foo = Exclude<"hello" | 0 | false, string | number>;

Foo型は以下のように定義できています。

// ①
type Foo = number
// ②
type Foo = number | boolean
// ③
type Foo = boolean
// ④
type Foo = false

NonNullable

型引数で指定した型からnullとundefinedを除いたもの

type Foo = NonNullable<string | null | undefined>;

Foo型は以下のように定義できています。

type Foo = string

Record

// 第一型引数がkey, 第二型引数がvalue
type Foo = Record<string, number>;

const obj: Foo = {
  hoge: 1,
  fuga: "2",
};

オブジェクト型のkeyとプロパティの型を指定できるようになります。

type Foo = {
    [x: string]: number;
}

そのため上記の例では以下のエラーができるようになります。

Type 'string' is not assignable to type 'number'.ts(2322)

Parameters

関数の引き数の型をTupleとして取得する

function foo(a: string, b: number[], c: boolean) {
  return;
}

type Foo = Parameters<typeof foo>;
type Foo = [a: string, b: number[], c: boolean]