> let n: number = 3;
> n = 'foo'
ts:5:1 - error TS2322: Type 'string' is not assignable to type 'number'
> const s = '123'; // 型アノテーションを省略しても型推論する
> const n = 456;
> s * 3
ts:6:1 - error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
> s + n
'123456' // 文字列の連結として返ってくる
・Boolean 型 …… true および false の 2 つの真偽値を扱うデータ型。型名は boolean ・Number 型 …… 数値を扱うためのデータ型。型名は number ・BigInt 型 …… number 型では表現できない大きな数値(253 以上)を扱う型。型名は bigint ・String 型 …… 文字列を扱うためのデータ型。型名は string ・Symbol 型 ……「シンボル値」という固有の識別子を表現する値の型。型名は symbol ・Null 型 …… 何のデータも含まれない状態を明示的に表す値。型名は null ・Undefined 型 ……「未定義」であることを表す値。型名は undefined
//配列の型アノテーション
> const numArr: number[] = [1, 2, 3];
//インタフェース オブジェクトの型に名前をつける
interface Color {
readonly rgb: string; //readonlyがつくと書き換え不可
opacity: number;
name?: string; //プロパティの最後に?がつくと省略可
}
const turquoise: Color = { rgb: '00afcc', opacity: 1 };
turquoise.name = 'Turquoise Blue';
turquoise.rgb = '03c1ff';
error TS2540: Cannot assign to 'rgb' because it is a read-only property.
//インデックスシグネチャ
interface Status {
level: number;
maxHP: number;
maxMP: number;
[attr: string]: number; //プロパティがstringで値がnumberを複数設定できる
};
const myStatus: Status = {
level: 99,
maxHP: 999,
maxMP: 999,
attack: 999,
defense: 999,
};
列挙したものの中からひとつに限定したい場合
//enumを使う
enum Pet {
Cat = 'Cat',
Dog = 'Dog',
Rabbit = 'Rabbit'
}
let Tom: Pet = Pet.Cat;
Tom = 'Hamster';
error TS2322: Type '"Hamster"' is not assignable to type 'Pet'.
Tom = 'Dog'; //'Dog'とPet.Dogは別物なのでエラーになる
error TS2322: Type '"Dog"' is not assignable to type 'Pet'.
//リテラル型を使う(型アノテーションで固定値を使う)
let Tom: 'Cat' = 'Cat';
Tom = 'Dog';
error TS2322: Type '"Dog"' is not assignable to type '"Cat"'.
let Mary: 'Cat'| 'Dog'| 'Rabbit' = 'Cat';
Mary = 'Rabbit';
Mary = 'Hamster';
error TS2322: Type '"Hamster"' is not assignable to type '"Cat" | "Dog" | "Rabbit"'.
個々の要素の型とその順番や要素数に制約を設けられる特殊な配列の型のこと
使い所は関数の引数とか(関数の引数を抽出するとタプル型で返ってくる)
const charAttrs: [number, string, boolean] = [1, 'patty', true];
//レストパラメータも使える
const spells: [number, ...string[]] = [7, 'heal', 'sizz', 'snooz'];
//any型。any はいかなる型の値でも受け付ける
let val: any = 100;
val = 'buz';
val = null;
//unkonwn型。anyの型安全版
const str = `{"id": 1, "username": "john_doe"}`;
const user: unknown = JSON.parse(str);
console.log(user.id, user.address.zipcode);
error TS2571: Object is of type 'unknown'. //コンパイル時にエラーになる。anyだとコンパイル時はエラーにならない
//never型。何も代入できない
//case のCheetah の2行を削除するとエディタでエラーを出してくれるので、case文漏れチェックできる
//cloud shellのエディタでもエラーだしてくれた
const greet = (friend: 'Serval' | 'Caracal' | 'Cheetah') => {
switch (friend) {
case 'Serval':
return `Hello, ${friend}!`;
case 'Caracal':
return `Hi, ${friend}!`;
case 'Cheetah':
return `Hiya, ${friend}!`;
default: {
const check: never = friend;
}
}
};
console.log(greet('Serval'));
// function declaration statement
{
function add(n: number, m: number): number {
return n + m;
}
console.log(add(2, 4)); // 6
}
// function keyword expression
{
const add = function(n: number, m: number): number {
return n + m;
};
console.log(add(5, 7)); // 12
}
// arrow function expression
{
const add = (n: number, m: number): number => n + m;
const hello = (): void => { //何も返さない関数の返り値はvoidになる
console.log('Hello!');
};
console.log(add(8, 1)); // 9
hello(); // Hello!
}
引数と戻り値をまとめて定義する
// callable object type
{
interface NumOp {
(n: number, m: number): number;
}
const add: NumOp = function (n, m) {
return n + m;
};
const subtract: NumOp = (n, m) => n - m;
console.log(add(1, 2)); // 3
console.log(subtract(7, 2)); // 5
}
// in-line
{
const add: (n: number, m: number) => number = function (n, m) {
return n + m;
};
const subtract: (n: number, m: number) => number = (n, m) => n - m;
console.log(add(3, 7)); // 10
console.log(subtract(10, 8)); // 2
}
型引数を用いて表現するデータ構造のことをジェネリクスという
> const toArray = <T>(arg1: T, arg2: T): T[] => [arg1, arg2]; //Tは型引数
> toArray(8, 3);
[ 8, 3 ]
> toArray('foo', 'bar');
[ 'foo', 'bar' ]
> toArray(5, 'bar');
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
//可変長引数
> const toArrayVariably = <T>(...args: T[]): T[] => [...args];
> toArrayVariably(1, 2, 3, 4, 5);
[ 1, 2, 3, 4, 5 ]
class Rectangle {
readonly name = 'rectangle';
sideA: number;
sideB: number;
constructor(sideA: number, sideB: number) {
this.sideA = sideA;
this.sideB = sideB;
}
getArea = (): number => this.sideA * this.sideB;
}
継承よりも合成を用いる
class Point {
x: number = 0;
y: number = 0;
}
const pointA = new Point();
const pointB: Point = { x: 2, y: 4 }; //クラスを型(インタフェース)として使用できる
interface Point3d extends Point {
z: number = 0;
}
const pointC: Point3d = { x: 5, y: 5, z: 10 };
type Unit = 'USD' | 'EUR' | 'JPY' | 'GBP';
type TCurrency = {
unit: Unit; // typeで定義した型を使用
amount: number;
};
interface ICurrency {
unit: Unit;
amount: number;
}
const priceA: TCurrency = { unit: 'JPY', amount: 1000 };
const priceB: ICurrency = { unit: 'USD', amount: 10 };
現在型エイリアスのほうがインタフェースよりできることが多いので、型エイリアス推奨
またインタフェースは拡張できてしまうので保守性が良くない
//インタフェースの拡張の例
interface User {
name: string;
}
//最初の定義から拡張できる
interface User {
age: number;
}
//最初の定義から拡張できる
interface User {
species: 'rabbit' | 'bear' | 'fox' | 'dog';
}
const rolley: User = {
name: 'Rolley Cocker',
age: 8,
species: 'dog',
};
// 共用体型。idはnumber, stringどちらもいける
> let id: number | string = 208239;
> id
208239
> id = 'a6ba7fb9-8435-4226-804e-387f3d2e53a7';
> id
'a6ba7fb9-8435-4226-804e-387f3d2e53a7'
// 交差型。numberかつstringを定義しているがそんなものは存在しないのでneverになる
> type Some = number & string;
> let id: Some;
> id = 100;
[eval].ts:3:1 - error TS2322: Type '100' is not assignable to type 'never'.
// ので基本的に交差型はオブジェクト型で使う
type A = { foo: number };
type B = { bar: string };
type C = {
foo?: number;
baz: boolean;
};
type AnB = A & B; // { foo: number, bar: string }
type AnC = A & C; // { foo: number, baz: boolean }
type CnAorB = C & (A | B);
// { foo: number, baz: boolean } or { foo?: number, bar: string, baz: boolean }
// オブジェクトの交差型の例2
type Unit = 'USD' | 'EUR' | 'JPY' | 'GBP';
interface Currency {
unit: Unit;
amount: number;
}
interface IPayment extends Currency {
date: Date;
}
type TPayment = Currency & { //インタフェースの拡張のようなことが交差型を使用してできる
date: Date;
};
const date = new Date('2020-09-01T12:00+0900');
const payA: IPayment = { unit: 'JPY', amount: 10000, date };
const payB: TPayment = { unit: 'USD', amount: 100, date };
デフォルトではNULLが変数に設定できてしまうのでtsconfig.jsonの以下設定をtrueにする
"strictNullChecks": true,
NULLを許容したい場合は共用体型で明示的に表現する
> let foo: string | null = 'fuu';
> foo = null;
// typeof
console.log(typeof 100); // 'number'
const arr = [1, 2, 3];
console.log(typeof arr); // 'object'
type NumArr = typeof arr; // numberの配列
const val: NumArr = [4, 5, 6];
const val2: NumArr = ['foo', 'bar', 'baz']; // NumArrはnumberの配列なのでcompile error!
// map type
const obj = { a: 1, b: 2, c: 3 };
console.log('a' in obj); // true 指定値がオブジェクトのキーに不クレマれるかどうかの真偽値
for (const key in obj) { console.log(key); } // a b c オブジェクトからキーを抽出
type Fig = 'one' | 'two' | 'three';
type FigMap = { [k in Fig]?: number }; // マップ型
const figMap: FigMap = {
one: 1,
two: 2,
three: 3,
};
figMap.four = 4; // compile error!
// keyof
const permissions = {
r: 0b100,
w: 0b010,
x: 0b001,
};
type PermsChar = keyof typeof permissions; // 'r' | 'w' | 'x'
const readable: PermsChar = 'r';
const writable: PermsChar = 'z'; // compile error!
// U extends T で第2引数のUは第一引数のTを拡張したのか同格のものである必要がある
const override = <T, U extends T>(obj1: T, obj2: U): T & U => ({
...obj1,
...obj2,
});
override({ a: 1 }, { a: 24, b: 8 }); // { a: 24, b: 8 }
override({ a: 2 }, { x: 73 }); // compile error!
//条件付き型 以下のような書き方もできる
//TがUを拡張していたら型X、そうでなければ型Y
T extends U ? X : Y
// テンプレートリテラル型
type DateFormat = `${number}-${number}-${number}`;
const date1: DateFormat = '2020-12-05';
const date2: DateFormat = 'Dec. 5, 2020'; // compile error!
・Partial<T> …… T のプロパティをすべて省略可能にする ・Required<T> …… T のプロパティをすべて必須にする ・Readonly<T> …… T のプロパティをすべて読み取り専用にする
type Partial<T> = { [K in keyof T]?: T[K] };
type Required<T> = { [K in keyof T]: T[K] };
type Readonly<T> = { readonly [K in keyof T]: T[K] };
・Pick<T,K> …… T から K が指定するキーのプロパティだけを抽出する ・Omit<T,K> …… T から K が指定するキーのプロパティを省く
type Todo = {
title: string;
description: string;
isDone: boolean;
};
type PickedTodo = Pick<Todo, 'title' | 'isDone'>;
type OmittedTodo = Omit<Todo, 'description'>;
// { title: string; isDone: boolean }
・Extract<T,U> …… T から U の要素だけを抽出する ・Exclude<T,U> …… T から U の要素を省く
type Permission = 'r' | 'w' | 'x';
type RW1 = Extract<Permission, 'r' | 'w'>;
type RW2 = Exclude<Permission, 'x'>;
// 'r' | 'w'
・NonNullable<T> …… T から null と undefined を省く
type T1 = NonNullable<string | number | undefined>;
type T2 = NonNullable<number[] | null | undefined>;
const str: T1 = undefined; // compile error!
const arr: T2 = null; // compile error!
・Record<K,T> …… K の要素をキーとしプロパティ値の型を T としたオブジェクトの型を作成す る
type Animal = 'cat' | 'dog' | 'rabbit';
type AnimalNote = Record<Animal, string>;
const animalKanji: AnimalNote = {
cat: '猫',
dog: '犬',
rabbit: '兎',
};
・Parameters<T> …… T の引数の型を抽出し、タプル型で返す ・ReturnType<T> …… T の戻り値の型を返す
const f1 = (a: number, b: string) => { console.log(a, b); };
const f2 = () => ({ x: 'hello', y: true });
type P1 = Parameters<typeof f1>; // [number, string]
type P2 = Parameters<typeof f2>; // []
type R1 = ReturnType<typeof f1>; // void
type R2 = ReturnType<typeof f2>; // { x: string; y: boolean }
・Uppercase<T> …… T の各要素の文字列をすべて大文字にする ・Lowercase<T> …… T の各要素の文字列をすべて小文字にする ・Capitalize<T> …… T の各要素の文字列の頭を大文字にする ・Uncapitalize<T> …… T の各要素の文字列の頭を小文字にする
type Company = 'Apple' | 'IBM' | 'GitHub';
type C1 = Lowercase<Company>; // 'apple' | 'ibm' | 'github'
type C2 = Uppercase<Company>; // 'APPLE' | 'IBM' | 'GITHUB'
type C3 = Uncapitalize<Company>; // 'apple' | 'iBM' | 'gitHub'
type C4 = Capitalize<C3>; // 'Apple' | 'IBM' | 'GitHub';
同じ関数名でも引数違いで複数定義できる
class Brooch {
pentagram = 'Silver Crystal';
}
type Compact = {
silverCrystal: boolean;
};
class CosmicCompact implements Compact {
silverCrystal = true;
cosmicPower = true;
}
class CrisisCompact implements Compact {
silverCrystal = true;
moonChalice = true;
}
function transform(): void;
function transform(item: Brooch): void;
function transform(item: Compact): void;
function transform(item?: Brooch | Compact): void {
if (item instanceof Brooch) {
console.log('Moon crystal power , make up!!');
} else if (item instanceof CosmicCompact) {
console.log('Moon cosmic power , make up!!!');
} else if (item instanceof CrisisCompact) {
console.log('Moon crisis , make up!');
} else if (!item) {
console.log('Moon prisim power , make up!');
} else {
console.log('Item is fake... ');
}
}
transform();
transform(new Brooch());
transform(new CosmicCompact());
transform(new CrisisCompact());