1
/
5

TypeScript最終回!

こんにちは! 株式会社アルシエで教育に関するサポートをしている岸本です。

今回はTypeScript最終回です。

Conditional Types

Conditional Typesとは、型の条件分岐を行なって型の推論を行うためのものです。

type Props = {
id: string;
name: string;
age: number;
};

上記のコードから、stringのkeyだけを抜き出すコードです。

type FilterString<T> = {
[K in keyof T]: T[K] extends string ? K : never;
}[keyof T];

// keys は "id" | "name"
type keys = FilterString<Props>

1️⃣ まず、<T>にはProps型をジェネリック型パラメータTに代入しています。

2️⃣ [K in keyof T]でPropsの"id" "name" "age"を取得し、Props型のキー(プロパティ名)を列挙しています

3️⃣ T[K]はLookup Typesです。TがPropsである場合、T['id']はstring、T['name']はstring、T['age']はnumberになります。

4️⃣ extends string ? K : neverについては、T[K]がstring型に割り当て可能である場合はK、そうでなければneverを返します。

5️⃣ T[K] extends string ? K : never; ←この書き方がConditional Typesです。

6️⃣ 最後に[keyof T]ですが、もし記述されてない場合は以下の型になります。

type keys = {
id: "id";
name: "name";
age: never;
}

[ keyof T ]は {} の中にある[K in keyof T]: T[K] extends string ? K : never;の結果、

type keys = { id: "id"; name: "name"; age: never; } に対して、Lookup Typesがされています。

infer

inferは関数の返り値の型を取得できます。

Tが制約を満たしていれば "U" を返して、満たしていなければ "never" を返します。

barが関数ではない場合は、neverになります。

// bar: () => string の stringだけを抽出したい
const bar = () => {
return ""
}

type Return<T> = T extends () => infer U ? U : never;

// Foo は string型
type Foo = Return<typeof bar>

引数の型だけの取得もできます。

infer Uは引数に記述する事ができます。

引数があり、numberを返す関数であれば "U" を返します。

const bar = (id:string) => {
return 0
}

type Return<T> = T extends (id:infer U) => number ? U : never;

// Foo は string
type Foo = Return<typeof bar>

引数が複数の場合

const bar = (id: string, name: number) => {
return 0;
};
// 残余引数で引数を取得
type Return<T> = T extends (...args: infer U) => any ? U : never;

// Foo は [id: string, name: number]
type Foo = Return<typeof bar>
type Return<T> = T extends (...args: infer U) => any ? U : never;

上記のコードを、毎回記述するのは大変だと思います。そんな時便利なのがUtility Types!

Utility Types

Utility Typesとはコード内で型変換を容易にする為にTypeScriptが提供する(便利な関数のような)型です。

Return

ReturnTypeとするだけで、関数の返り値の型を取得できます。

const bar = (id: string, name: string) => {
return "0";
};

// Foo は string
type Foo = ReturnType<typeof bar>;

Readonly

Readonlyとは全てのプロパティをreadonlyのプロパティにしてくれます。

type Todo = {
title: string
};
const todo: Readonly<Todo> = {
title: '家の掃除',
};

// 読み取り専用プロパティであるため、title に代入することはできません。
todo.title = '夕飯の買い出し';

Partial

Partialは、全てのプロパティをOptionalにします。

type Person = {
firstName: string;
lastName: string;
age: number;
};

const taro: Partial<Person> = {
firstName: "Taro",
};

Required

Requiredは、全てのプロパティを必須にします。

type Person = { 
firstName?: string
lastName?: string
}

// 'lastName' はここで宣言されています。
const jiro: Required<Person> = {
firstName: 'Taro',
}

Pick

Pickは、Pick<T,K>は既に存在するT型の中からKで選択した一部のプロパティのみを含んだ新たな型を構築します。

type Todo = {
title: string
description: string
completed: boolean
}

// type TodoPreview = {
// title: string;
// completed: boolean;
//}
type TodoPreview = Pick<Todo, 'title' | 'completed'>

Omit

Omit<T,K>は既に存在するT型の中からKで選択した一部のプロパティを除いた新たな型を構築します。

type Todo = {
title: string;
description: string;
completed: boolean;
};

// type TodoPreview = {
// description: string;
// }
type TodoPreview = Omit<Todo, "title" | "completed">;

他にも便利なUtility Typesや型を拡張するためのアンビエント宣言・namespaceがありますので、調べてみてください。

TypeScriptに関しては、以上となります。

ご覧いただきありがとうございました!

Invitation from 株式会社アルシエ
If this story triggered your interest, have a chat with the team?
株式会社アルシエ's job postings
3 Likes
3 Likes

Weekly ranking

Show other rankings
Like Naomichi Totsuka's Story
Let Naomichi Totsuka's company know you're interested in their content