同じ日に複数の言語を使って開発作業をすることはよくあります。
その時に、どう書けるのか分からなくなることが多く、都度調べつつ作業をすることが多いです。
その調べる時間を削減するために、個人的なメモのような形でまとめていきたいと思います。
触れない内容
- index.d.ts
- @types
- interface が良いか、type が良いか
- JavaScript の書き方 や 基礎知識
- 細かいロジックや説明
参考サイト
基本的な使い方
let 変数名: 型;
let 配列変数名: 型[];
class クラス名 {
変数名: 型;
}
const func = (引数名: 引数型): 戻り値型 => {
return 戻り値;
};
処理の IN/OUT を制限して内部で利用する
function hello(name: string, helloAfterAction: (name: string) => number) {
console.log(`hello ${name}`);
helloAfterAction(name);
}
// interfaceのように定義する
type HogeInterface = (hoge: string) => number;
type FugaInterface = {
(hoge: string): number;
};
function hogee(name; string, hogeAction: HogeInterface) {
console.log(`hogee ${name}`);
hogeAction(name);
}
A or B
ユニオン型(Union type)
let hoge: A | B;
配列の中身が A or B
let hoge: (A | B)[];
A or 値なし(未定義)
オプション(Optional)
class Hoge {
hoge?: A;
}
class Fuga {
hoge: A | undefined;
}
// A or undefined だけど、明示的な値定義を強制する
class Piyo {
hoge?: A | undefined;
}
デフォルト値設定
function hello(name?: string) {
name ??= 'ほげ';
}
function hello(name: string = "ほげ") {
}
値がない状態(null or undefined)でも安全に利用する
オプショナルチェーン(Optional Chain)
Null合体演算子
let hoge: undefined;
let typeVal: string | undefined = hoge?.title?.type;
let typeNumber: number = typeVal?.indexOf("ほ") ?? 0;
A であり B であるもの
交差型・インターセクション型(intersection type)
type Hoge = A & B;
function extend<A, B>(first: A, second: B): A & B {
return { ...first, ...second };
}
※ 判別できない型が出来上がった場合、 never型として扱われる
特定の型が利用時に決まる
総称型(Generics)
function hello<T>(arg: T): string {
return `hello ${arg}!`;
}
class Hoge<T> {
private name: string;
private hoge: T;
constructor(name: string, hoge: T) {
this.name = name;
this.hoge = hoge;
}
}
// 利用時
hello<string>("hoge");
new Hoge<number>("hoge", 1);
型の定義方法
型を作る
type Hoge = {
name: string;
};
実体を持つ型を作る
class Hoge {
hoge: string;
}
振舞いを強制できる型を作る
interface Hoge {
hoge: string;
}
利用できる値を制限する
"hoge" or "fuga" しか受け付けない
リテラル型
const hello = (name: "hoge" | "fuga") => {
console.log(`hello ${name}`);
};
※ string , number , boolean が実際に利用できる値として制限できる
決められた値 しか受け付けない
Enum
enum Username {
Hoge = "hoge",
Fuga = "fuga",
}
namespace Username {
/** Username.hello(Username.Hoge); ができるようになる */
export function hello(name: Username): string {
return `hello ${name}`;
}
}
※ Enum のようなinterface
interface ValueType;
const Enum = {
key: {
...
} as ValueType,
} as const;
type Enum = typeof Enum[keyof typeof Enum];
※ Enumのように使え、文字列でも定義できるようにする
function stringToEnum<T extends string>(o: T[]): { [K in T]: K } {
return o.reduce((accumulator, currentValue) => {
accumulator[currentValue] = currentValue;
return accumulator;
}, Object.create(null));
}
const Hoge = stringToEnum(["hoge", "fuga"]);
type Hoge = keyof typeof Hoge;
※ https://basarat.gitbook.io/typescript/type-system/literal-types#string-based-enums を引用
同じ型を複数受け付ける
可変長引数・残余引数(rest parameter)
function hello(name: string, ...greetedName: string[]) {
}
型判定方法
プリミティブレベルでの確認
let isString: boolean = typeof "" === 'string';
型 | 判定用文字列 |
---|---|
文字列 | 'string' |
真偽値 | 'boolean' |
数値 | 'number' |
undefined | 'undefined' |
null | 'object' |
BigInt | 'bigint' |
関数 | 'function' |
Symbol | 'symbol' |
その他 | 'object' |
ざっくり継承関係での確認
let val: Hoge = ...;
let isHoge: boolean = val instanceof Hoge;
let isNotHoge: boolean = !(val instanceof Hoge);
プロパティの存在確認
let hasName: boolean = 'name' in val;
チェック処理を挟んだ後の型を確定させて利用する
class Hoge {
static isType(arg: any): arg as Hoge {
let isNotNullObj: boolean = (arg === 'object' && arg !== null);
return isNotNullObj &&
typeof (arg as Hoge).name === 'string';
};
}
let val = ...;
if (Hoge.isType(val)) {
// このスコープ内では、val を Hoge として扱うことができる
}
データのやり取りを行うための型
class で定義する
class Hoge {
hoge: string;
constructor(init?: Partial<Hoge>) {
Object.assign(this, init);
}
}
(() => {
let hoge: Hoge = new Hoge({
hoge: "fuga"
});
})();
interface で定義する
interface Hoge {
hoge: string;
}
(() => {
let hoge: Hoge = {
hoge: "fuga"
};
})();
使い捨て前提で定義する
インライン型アノテーション(Inline Type Annotation)
(() => {
let hoge: {
hoge: string;
} = {
hoge: "fuga"
};
})();
戻り値の型を複数にする(配列活用)
タプル(Tuple)
let [id, name, type]: [string, number, string] = ((val: string): [string, number, string] => {
return [0, "hoge", "fuga"];
})("");
戻り値の型を複数にする
分割代入(destructring)
let {id, name, type} = ((val: string): { id: number, name: string, type: string } => {
return {
id: 0,
name: "hoge",
type: "fuga",
};
})("");
最後に
ある程度経験を積んでいくと基本の部分を忘れている場面は多々あります。簡単に調べることは可能ですが、できる限りその時間を短縮していきたいですね。
新しい記法が増えていく可能性もあるため、今回まとめた内容では足りていない部分があるかもしれません。
不足や他にも良い定義方法がありましたら教えていただけますと幸いです。