TypeScript入門 【組み込みユーティリティ&型アサーションと型ガード】
今回はTypeScriptの組み込みユーティリティと、型ガードについて説明していきます。
どちらも現場では良く見るコードなので、一緒に学んでいきましょう。
組み込みユーティリティ
まずはジャンル毎に組み込みユーティリティをいくつか紹介します。
オブジェクト型
よく使われるオブジェクト型に使う組み込みユーティリティを次の3つです。
- Partial …… T のプロパティをすべて省略可能にする
- Required …… T のプロパティをすべて必須にする
- Readonly …… T のプロパティをすべて読み取り専用にする
それぞれ以下のように使います。
type nameType = {
firstName?: string;
lastName: string;
};
//全て省略可能
const name0: Partial<nameType> = {};
//全て省略不可
const name1: Required<nameType> = {
firstName: "shiya",
lastName: "hinohara"
};
//型は元のまま 値の変更が不可になる
const name2: Readonly<nameType> = {
lastName: "hinohara"
};
また、次の3つも結構使われます。
- Pick …… T から K が指定するキーのプロパティだけを抽出する
- Omit …… T から K が指定するキーのプロパティを省く
- Record …… K の要素をキーとしプロパティ値の型を T としたオブジェクトの型を作成する
それぞれ実際に使うと次のようになります。
type userType = {
firstName?: string;
lastName: string;
type: string;
};
// 元の方からいくつかを取り出せる
const nameProp: Pick<userType, "firstName" | "lastName"> = {
firstName: "shinya",
lastName: "hinohara"
};
// Omitでも表現できる
const nameProp2: Omit<userType, "type"> = {
firstName: "shinya",
lastName: "hinohara"
};
// number型がプロパティとなり、userTypeをもつ型となります。
type userList = Record<number, userType>;
const users = { 0: { firstName: "taro", lastName: "sato", type: "free" } };
列挙型
次に列挙型に使う組み込みユーティリティをいくつか紹介します。
- Extract …… T から U の要素だけを抽出する
- Exclude …… T から U の要素を省く
- NonNullable …… T から null と undefined を省く
実際に使うと次のようになります。
type hoby = "reading" | "traveling" | null | undefined;
const myHoby: Extract<hoby, "reading"> = "reading";
const myHoby2: Exclude<hoby, "reading"> = "traveling";
const hobies: NonNullable<hoby> = "reading";
後、次の4つも覚えておいて損はないです。
- Uppercase …… T の各要素の文字列をすべて大文字にする
- Lowercase …… T の各要素の文字列をすべて小文字にする
- Capitalize …… T の各要素の文字列の頭を大文字にする
- Uncapitalize …… T の各要素の文字列の頭を小文字にする
例
type countries1 = "japan" | "USA" | "chiNese";
// type countries2 = "USA" | "JAPAN" | "CHINESE"
type countries2 = Uppercase<countries1>;
// type countries3 = "japan" | "usa" | "chinese"
type countries3 = Lowercase<countries1>;
// type countries4 = "USA" | "Japan" | "ChiNese"
type countries4 = Capitalize<countries1>;
// type countries5 = "japan" | "chiNese" | "uSA"
type countries5 = Uncapitalize<countries1>;
関数
最後に関数に使う組み込みユーティリティをいくつか紹介します。
- Parameters …… T の引数の型を抽出し、タプル型で返す
- ReturnType …… T の戻り値の型を返す
それぞれ実際に使うと
const plus = (num1: number, num2: number): number => {
return num1 + num2;
};
// type plusType = [num1: number, num2: number]
type plusType = Parameters<typeof plus>;
// type plusReturn = number
type plusReturn = ReturnType<typeof plus>;
型アサーションと型ガード
次に型アサーションと型ガードについて説明します。
型アサーションはas ~と書く事で、コンパイラによる型の解釈が変える手法になります。
このasのはT as (U extends T)または(T extends U) as Uであるとき、つまりTがUのサブタイプであるかUがTのサブタイプである場合にしか使えないものなります。
実際に見ないと良く分からないと思うので、次の例を見てください。
// myCountry=stringとコンパイラに伝える
const myCountry = "japan" as string;
// TがUのサブタイプでもUがTのサブタイプでもないのでエラーになる
const test = 1 as string;
この型アサーションは一見あまり使いどころが内容に思えますが、型ガードをする時に便利です。
型ガードとは、Unknown型を使うための型を保証するチェックのことです。
これも実際に例を見て見ましょう。
const myname: unknown = "taro";
// プリミティブ型(null以外)の型ガードにはtytpeofが使える
if (typeof myname === "string") {
console.log("hello");
}
class User {
name: string;
height: number;
constructor(name: string, height: number) {
this.name = name;
this.height = height;
}
}
const user1: unknown = new User("taro", 173);
// クラスの型ガードにはinstanceofが使える
if (user1 instanceof User) {
console.log("hello2");
}
しかし、ただのオブジェクトに対して型ガードしたい時は、自前で型を絞り込むしくみを作ってあげる必要があります。
それは『ユーザー定義の型ガード』と呼ばれる方法で、次の通りです。
type User = { username: string; address: { zipcode: string; town: string } };
const isUser = (arg: unknown): arg is User => {
const u = arg as User;
return (
typeof u?.username === "string" &&
typeof u?.address?.zipcode === "string" &&
typeof u?.address?.town === "string"
);
};
const u: unknown = JSON.parse(
'{ "username": "patty", "address": { "zipcode": "111", "town": "Maple Town" } }'
);
if (isUser(u)) {
console.log("heloo");
}
関数 isUser()の戻り値の型定義がarg is Userという見慣れない記述になっていますが、これは型述語という表現で、この関数がtrueを返す場合に引数 argの型がUserであることがコンパイラに伝えることができます。
以上。
最後に宣伝です。
0からエンジニアになるためのノウハウをブログで発信しています。
また、YouTubeでの動画解説も始めました。
YouTubeのvideoIDが不正ですインスタの発信も細々とやっています。
興味がある方は、ぜひリンクをクリックして確認してみてください!
おわり
Discussion