TypeScriptの勉強を開始したばかりのビギナーです。
TypeScriptを使用するなら、「最初に型
を抑えておくべき」と思い、型の種類を調べてみました。
基本
プリミティブ型
// 真偽値 const bool1: boolean = true; const bool2: boolean = false; const bool3: boolean = null; // or undefined // ※ // 数値型 const num1: number = 10; const num2: number = 0b1010; const num3: number = 0o12; const num4: number = 0xa; const num5: number = null; // or undefined // ※ // BigInt(任意精度整数)/* targetがES2020未満の場合は使用不可 */ const bi1: bigint = BigInt(100); const bi2: bigint = 100n; const bi3: bigint = null; // or undefined // ※ // 文字列型 const str1: string = 'Hello'; const str2: string = "World!"; const str3: string = `${str1} ${str2}`; const str4: string = null; // or undefined // ※ // null const n1: null = null; const n2: null = undefined; // ※ // undefined const u1: undefined = null; // ※ const u2: undefined = undefined; // symbol const sym1: symbol = Symbol(); const sym2: symbol = Symbol('key');
- ※
strictNullChecks
を有効化しているとコンパイルエラーになります。
リテラル型
- リテラル型とは、プリミティブ型の特定の値だけを代入可能にする型の表現のことです。
プリミティブ型の例
let x: number; x = 1;
リテラル型の例(1だけが代入可能な型を作成する例)
let x: 1; x = 1; x = 100; // Type '100' is not assignable to type '1'.
リテラル型として表現できるプリミティブ型は次のとおりです。
- boolean型のtrueとfalse
- number型の値
- string型の文字列
const isTrue: true = true; const num: 123 = 123; const str: "foo" = "foo";
リテラル型の用途
let num: 1 | 2 | 3 = 1;
配列型
- 以下の二つの方法で表現することができる。書き方以外に違いはありません。
- ある型の後に
[]
と記述する - ジェネリクスを使用する
- ある型の後に
// []を使った定義 const arr1: number[] = [1, 2, 3]; // ジェネリクスを使った定義 const arr2: Array<number> = [1, 2, 3];
オブジェクト型
- TypeScriptでは
{}
の中にプロパティと値の型を列挙することとで、オブジェクトを表現できます。
function getAge(user:{age: number}){ return user.age; } const user1 = {age:17}; const user2 = {age:27,name:`taro`}; const user3 = {age:37,birthday:1231}; getAge(user1); getAge(user2); getAge(user3);
- 上記の例では
{age: number}
の部分がオブジェクト型の表現になります。 user2
、user3
は余分なプロパティを持ってはいますが、必要とされる構造は満たしているのでコンパイルに成功します。
interface(型の構造に名前を付ける)
- プロパティに対して
?
をつけることで「省略可能なプロパティ(オプションプロパティ)」を表現することができます。 - オプションプロパティは指定した型以外に
undefined
になる可能性を持ちます。
interface User{ age: number; } function getAge2(user: User){ return user.age; }
オプションプロパティ(省略可能なプロパティ)
- プロパティに対して
?
をつけることで「省略可能なプロパティ(オプションプロパティ)」を表現することができます。 - オプションプロパティは指定した型以外に
undefined
になる可能性を持ちます。
interface User{ age: number; name: string; birthday?: number; }
インデックスシグネチャ(動的なプロパティ)
- 動的なプロパティを型として表現できる。
interface StringDictionary{ [key: string]: string; } const dic :StringDictionary = {}; dic['key1'] = 'value1'; dic['key2'] = 'value2'; dic['key3'] = 3; // コンパイルエラー
- インデックスシグネチャと明示的に宣言されたプロパティを併用した場合、明示的に宣言されたプロパティが優先されます。
any型
- すべての型に適合する特殊な型
- 何でもありになってしまうため極力避けてください。
- JavaScriptプロジェクトを移行する過程などで一時的にコンパイルを通して先に進みたい時などに有効。
let samething: any = 10; samething = false; samething = "Hello World!";
void型
- 値を返さないことを表現する型。
function greet():void{ console.log('Hello World') }
列挙型
- 値の集合を表現する。
文字列列挙型
- イニシャライザに文字列を指定
enum week1 { Mon = 'mon', Tue = 'tue', Wed = 'wed', Thu = 'thu', Fri = 'fri', Sat = 'sat', Sun = 'sun', };
数値列挙型
- イニシャライザを完全に省略
enum week2 { Mon, // 0 Tue, // 1 Wed, // 2 Thu, // 3 Fri, // 4 Sat, // 5 Sun, // 6 };
- イニシャライザに数値を指定
enum week3 { Mon, // 0 Tue, // 1 Wed = 10, // 10 Thu, // 11 Fri, // 12 Sat = 20, // 20 Sun, // 21 };
関数型
- 関数の型を表現する
関数型の宣言
const add1:( x: number, y: number, ) => number = function (x: number, y:number): number{ return x + y; }
関数型とアロー関数の使用
const add2:( x: number, y: number, ) => number = (x: number, y:number): number => { return x + y; }
型推論によって型注釈を省略可能
const add3:( x: number, y: number, ) => number = (x, y) => { return x + y; }
オブジェクト型に関数型を含める
interface Adder{ (x: number,y: number): number; } const add: Adder = (x, y) =>{ return x + y; }
省略可能な引数
- オブジェクト型と同様に、?で省略可能な引数を宣言できます。
const multiply1: ( x: number, y?: number, ) => number = (x, y) => { return x * (y !== undefined ? y : 1); };
- 以下の記述だと引数が1個の場合にエラーになります。
const multiply2: ( x?: number, y: number, z?: number, ) => number = (x, y, z) => { return (x !== undefined ? x : 1) * (y !== undefined ? y : 1) * (z !== undefined ? z : 1); }; multiply2(100); //2-3 個の引数が必要ですが、1 個指定されました。ts(2554) multiply2(100,100); multiply2(100,100,100);
可変長引数
- 可変長引数は必ず任意の配列型として引数の最後に定義します。
const log1:( format: string, ...value:any[], ) => void = (format,...values) => { console.log(format,...values); }; log1('Hello'); log1('Hello %s', 'World');
クラス
- TypScriptを使ったクラスの例
class Point { public x: number; public y: number; public constructor(x: number,y: number){ this.x = x; this.y = y; } public offset(dx: number, dy: number):void { this.x += dx; this.y += dy; } } const point = new Point(5, 10); point.offset(15, 20);
- implementsを使ってクラスに構造を強制させる
interface Serializable { serialize(): string; } // serializeメソッドの実装が強制される class TypeA implements Serializable { serialize(): string { return 'TypeA'; } } class TypeB implements Serializable { serialize(): string { return 'TypeB'; } } function debug(values: Serializable[]){ values.forEach((value)=> { console.log(value.serialize()); }); } debug([new TypeA(), new TypeB()]);
- クラスと同名の型が宣言される
class Dog { bark(){ console.log('bowwow!'); } } const dog: Dog = new Dog(); dog.bark();
型の組み合わせ
union型(合併型)
- 指定された型の中からいづれかを満たす型を表現する
- 複数の型を
|
でつないで定義する
- 複数の型を
- JavaScriptを使ったプログラミングでは、引数や戻り値が複数の型になりえるパターンが多数存在しますが、any型を使うと型検査で検出できる不整合が限られてしまう
- union型を使用することで、複数の型を許容することができる
function stringify(value: string| string[]): string{ if(Array.isArray(value)){ return value.join(', '); } return value; } stringify('Hello'); stringify(['Hello','World']);
intersection型(交差型)
- 指定された型をすべて満たす型を表現する型
- 複数の型を
&
でつないで定義する
- 複数の型を
interface Name{ name: String; } interface Address { address: string; } const nameNumberAddress: Name & Address = { name: 'Taro', address: 'Tokyo', };