意味のある共通のプロパティをもたせて判別に使う。
interface Bird {
flySpped: number;
type: "bird";
}
interface Horse {
runSpeed: number;
type: "horse";
}
type Animal = Bird | Horse;
function animalSpeed(animal: Animal) {
switch (animal.type) {
case "bird":
console.log(animal.flySpped);
break;
case "horse":
console.log(animal.runSpeed);
}
}
文字列を数値に変換する場合、 +
を変数の前につけるだけでよい。
const a = "1";
const b = "2";
const result = +a + +b;
console.log(result); // 3
前に <>
で型を書くか、後ろに as
を付けて型キャストできる。
祖運剤が確定している場合は !
を付けてエラーを回避できる。
const input1 = <HTMLInputElement> document.getElementById("num")!;
const input2 = document.getElementById("num")! as HTMLInputElement;
interface ErrorInterface {
[prop: string]: string;
}
const errorMessage: ErrorInterface = {
email: "hoge",
name: "foo",
message: "fuga",
};
console.log(errorMessage); // { email: "hoge", name: "foo", message: "fuga" }
受け取る型と返す型のパターンを関数の直前に記述する。
type Input = string | number;
function add(a: number, b: number): number;
function add(a: string, b: number): string;
function add(a: number, b: string): string;
function add(a: string, b: string): string;
function add(a: Input, b: Input) {
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString();
}
return a + b;
}
console.log(add(1, 2));
console.log(add("1", 2));
?
を使ってオブジェクトに安全にアクセスする。
const fetched = {
id: "id1",
name: "hoge",
job: {
title: "Dev",
desc: "developer",
},
};
console.log(fetched && fetched.job && fetched.job.title);
console.log(fetched?.job?.title);
null
か undefined
のときのみ判定できる。
let input = "";
const inputData = input ?? "Default";
console.log(inputData);
class Person {
id: string;
name: string;
constructor(id: string, n: string) {
this.id = id;
this.name = n;
}
printData() {
console.log(`ID: ${this.id}; Name: ${this.name}`);
}
}
const person = new Person("user1", "hoge");
person.printData(); // ID: user1; Name: hoge
フィールドとコンストラクタはまとめる事ができる。やり方は constractor
にアクセス修飾子を書くだけ。
引数の名前はフィールド名にしないといけない。
class Person {
constructor(public id: string, public name: string) {
}
printData() {
console.log(`ID: ${this.id}; Name: ${this.name}`);
}
}
const person = new Person("user1", "hoge");
person.printData(); // ID: user1; Name: hoge
private
は外部からアクセスできない。 readonly
は初期化後に変更ができない。
また protected
はサブクラスからのみアクセス可能。
class Person {
constructor(private readonly id: string, public name: string) {
}
printData() {
console.log(`ID: ${this.id}; Name: ${this.name}`);
}
}
const person = new Person("user1", "hoge");
person.printData(); // ID: user1; Name: hoge
()
は不要。プロパティのように実行する。
class Person {
private _report: string;
constructor(private readonly id: string, public name: string) {
this._report = "";
}
get report() {
return this._report;
}
set report(input: string) {
this._report = input;
}
printData() {
console.log(`ID: ${this.id}; Name: ${this.name}`);
}
}
const person = new Person("user1", "hoge");
person.printData(); // ID: user1; Name: hoge
person.report = "report1";
console.log(person.report); // report1
static メソッドや static プロパティには this でアクセスできない ( インスタンスからアクセスできない )。
class Person {
static year = 2021;
}
console.log(Person.year); // 2021
抽象メソッドは抽象クラス内でのみ使える。抽象メソッドは関数の構造のみを定義しておく。 抽象クラスからはインスタンスを作れない。継承したサブクラスからはインスタンスを作れる。
abstract class Product {
constructor(protected readonly id: string, public name: string) {
}
abstract describe(): void;
}
class Product1 extends Product {
constructor(id: string, name: string) {
super(id, name);
}
describe(): void {
console.log(`ID: ${this.id}; Name: ${this.name}`);
}
}
const product1 = new Product1("1", "hoge");
product1.describe(); // ID: 1; Name: hoge
オブジェクトを 1 つしか作らせたくない場合に使う。
class Person {
private static instance: Person;
static getInstance() {
if (Person.instance) {
return this.instance;
}
this.instance = new Person();
return this.instance;
}
}
const person = new Person();
オブジェクトがどんな形であるか定義する。 interface とカスタムタイプの使い分けは、オブジェクトの構造を記述するときは interface を使う。 カスタムタイプは union 型など様々な型を定義できる。 interface を使えばオブジェクトの構造を定義したいという意図を明確にできる。 また interface は readonly 継承もできる。
interface Named {
readonly name: string
}
interface Greetable extends Named {
hello(phrase: string): void
}
implements
を使って実装する。
抽象クラスとの違いは、 interface では値や実装を持たない。抽象クラスは値や実装を混在させる事ができる。
interface PersonInterface {
id: string;
name: string;
describe(): void;
}
class Person implements PersonInterface {
id: string;
name: string;
constructor(id: string, n: string) {
this.id = id;
this.name = n;
}
describe(): void {
console.log(`ID: ${this.id}; Name: ${this.name}`);
}
}
const person = new Person("1", "hoge");
person.describe(); // ID: 1; Name: hoge
関数の後ろに <>
を付けて表現する。
function mergeObject(objA: object, objB: object) {
return Object.assign(objA, objB);
}
console.log(mergeObject({ id: "1" }, { name: "hoge" })); // { id: "1", name: "hoge" }
function mergeObject<T>(objA: T, objB: T) {
return Object.assign(objA, objB);
}
console.log(mergeObject({ id: "1" }, { name: "hoge" })); // { id: "1", name: "hoge" }
extends を使う。
function mergeObject<T extends object, U extends object>(objA: T, objB: U) {
return Object.assign(objA, objB);
}
console.log(mergeObject({ id: "1" }, { name: "hoge" })); // { id: "1", name: "hoge" }
keyof
を使うことでオブジェクトのキーの制約を持たせる。
function addConvert<T extends object, U extends keyof T>(obj: T, key: U) {
return "value: " + obj[key];
}
console.log(addConvert({ id: "1", name: "hoge" }, "name")); // value: hoge
クラスの後ろに <>
を付けて表現する。
class DataStore<T extends string | number> {
private data: T[] = [];
addItem(item: T) {
this.data.push(item);
}
removeItem(item: T) {
if (this.data.indexOf(item) === -1) {
return;
}
this.data.splice(this.data.indexOf(item), 1);
}
getItems() {
return [...this.data];
}
}
const stringDate = new DataStore<string>();
const numberData = new DataStore<number>();
stringDate.addItem("data1");
stringDate.addItem("data2");
numberData.addItem(1);
numberData.addItem(2);
stringDate.removeItem("data2");
numberData.removeItem(2);
console.log(stringDate.getItems()); // [ "data1" ]
console.log(numberData.getItems()); // [ 1 ]
一時的に別の型に切り替えることができる。
Partial
で最終的にキャストされる型を指定する。
return するときはキャストが必要。
interface Todo {
title: string;
desc: string;
date: Date;
}
function createTodo(
title: string,
desc: string,
date: Date,
): Todo {
let todo: Partial<Todo> = {};
todo.title = title;
todo.desc = desc;
todo.date = date;
return todo as Todo;
}