こんにちは、フロントエンドエンジニアのてりーです。
クラスの型定義について復習
前回に記事ではTypeScriptにおける、関数とクラスの基本的な型の定義方法と、クラスの継承・合成についてみていきました。
【TypeScript入門】クラスの型定義(インターフェースと型エイリアスの違い)
この記事の中で、クラスは型定義を目的とした抽象クラスと、実装部分の2通りに分かれると伝えました。
今回はこの部分を詳しく見ていきましょう。
インターフェース
抽象クラスには現状でabstract修飾子を使った方法と、インターフェースを使った方法があります。
abstract修飾子を使った方法は抽象クラスでありながら、実装部分を含む事ができる為、保守性を考えて現状ではあまり使われていません。
今回はインターフェースのみを説明していきます。
//インターフェースにてShapreを定義
interface Shape {
readonly name: string;
getArea: () => number;
}
//インターフェースにてQuadrangleを定義
interface Quadrangle {
side: number;
}
//Rectabgleクラスには抽象クラスのShapreとQuadrangleの型を使う!!
class Rectangle implements Shape, Quadrangle {
readonly name = 'rectangle';
side: number;
sideB: number;
constructor(side: number, sideB: number) {
this.side = side;
this.sideB = sideB;
}
getArea = (): number => this.side * this.sideB;
}
const rect = new Rectangle(6, 5);
console.log(rect.getArea());
この様に
interface Quadrangle {
side: number;
}
で定義できて、
class Rectangle implements Quadrangle { }
で使う事ができる!!詳しい使い方などはこちらの記事が参考になります。
型エイリアス
任意の型に別名を与えて再利用できるものを「型エイリアス」と呼びます。
定義の仕方はインターフェース同様です。
type Enemy = {
hp: number
mp: number
}
インターフェースと型エイリアスの違い
基本的に、現在ではインタフェースよりも型エイリアスの方ができる事が多いです。
その上で型エイリアスの方が柔軟性と保守性が高い為、モダンな環境では型エイリアスの方が好まれています。
それぞれの違いについてみていきましょう。
型エイリアスは任意の型を定義できる
type Unit = 'USD' | 'EUR' | 'JPY' | 'GBP';
などの様にリテラル型なども使えます。インターフェースではオブジェクトとクラスのみしか参照できません。
インターフェースは既存の方を名前を変えずに拡張できてしまいます。
interface User {
age: number;
}
interface User {
species: 'rabbit' | 'bear' | 'fox' | 'dog';
}
型エイリアスはユニオン型とインターセクションで複雑な型表現ができる
ユニオン型
ユニオン型が『A または B』と適用範囲を増やしていく型の表現方法です。
type A = {
foo: number;
bar?: string;
};
type B = { foo: string };
type C = { bar: string };
type D = { baz: boolean };
typeAorB=A|B; //ユニオン型AまたはB{foo:number|string;bar?:string}
typeAorC=A|C; //ユニオン型AまたはC{{foo:number;bar?:string}or{bar:string}
typeAorD=A|D; //ユニオン型AまたはD{{foo:number;bar?:string}or{baz:boolean}
インターセクション型
インターセクション型は『A かつ B』と複数の型をひとつに結合させる事ができます。
→オブジェクト型の合成が可能になります。
type A = { foo: number };
type B = { bar: string };
type C = {
foo?: number;
baz: boolean;
};
typeAnB=A&B; //インターセクション型AかつB{foo:number,bar:string}
typeAnC=A&C; //インターセクション型AかつC{foo:number,baz:boolean}
ユニオン型とインターセクション型を組み合わせることで、複雑な型表現も可能です。
type A = { foo: number };
type B = { bar: string };
type C = {
foo?: number;
baz: boolean;
};
typeCnAorB=C&(A|B);
// Cかつ(AまたはB)
//{ foo: number, baz: boolean } or { foo?: number, bar: string, baz: boolean }
型の Null 安全性を保証する
TypeScript はデフォルトの設定ではすべての型に null と undefined を代入できてしまいます。
このままだと静的型付け言語の特徴でもあるnull安全性を担保できません。
対策として、コンパイラオプション strictNullChecks を設定する必要があります。
りあクト! TypeScriptで始めるつらくないReact開発 第3版【Ⅰ. 言語・環境編】
tsconfig.json ファイルに対して次の様に記述してください。
"strictNullChecks": true,
もしnullを許容したい場合はこの様に書けばOKです。
let foo: string | null = 'fuu';
まとめ
今回はクラスの型定義の方法となる
・インターフェース
・型エイリアス
についてをメインに解説していきました。
現状では、型エイリアスの方が機能として優れていると説明しましたが、現場レベルではまだまだインターフェースが使われている場合もある為、今回はインターフェースの解説も混ぜました。
もし、新しくコードを書く際があれば、型エイリアスでの書き方をお勧めします。
また、今回の記事で、TypeScriptの基本的な型は全て解説しました。
ここまでの内容を抑えていれば、TypeScriptのコードを読む際にもわかる事が増えていると思います。
次回以降は応用編として、より高度な型表現を解説していきます。
以上です。
TypeScriptの入門記事一覧
・【TypeScript入門】JavaScriptとの違いや特徴を詳しく解説
・【TypeScript入門】基本的な型の定義方法
・【TypeScript入門】関数とクラスの型定義(継承と合成)
・【TypeScript入門】クラスの型定義(インターフェースと型エイリアスの違い)
・【TypeScript】高度な型表現について
・【TypeScript】型ガードと型アサーションでunknown型を使い勝手良くする