🐙
TypeScriptを雰囲気で使っていたので勉強し直したら知らなかったこと
TypeScript Version 4.3.4で動作確認
object型
let user = { name: "hoge" };
と
let user: { name: string } = { name: "hoge" };
は同義である。JSでいうところのobjectを定義すると{ name: string }
という型が暗黙的に定義されたことになる。
リテラル型
値を指定する型のこと。決まった値しか使わせたくない場合に使用する。
let x: "hoge" | "piyo";
x = "hoge"
x = "piyo"
x = "fuga" // エラー
unknown型
型が不定の型。何でも代入できるが使用するときや、他の変数に代入するときに型ガードが必要。
let x: unknown = "hoge";
// x.toUpperCase(); これはコンパイルでエラー
if (typeof x == "string") {
x.toUpperCase();
}
anyはコンパイルではエラーにならないが、実行時にエラーになる
let x: any = 1;
x.toUpperCase();
never型
関数やメソッドが正常に終了しないことを明示的に指定するための型
これだと正常に終了してしまうのでコンパイルでエラー
const hoge = (): never => {
};
必ず例外を投げる関数などを定義するときに使用する
const hoge = (): never => {
throw Error();
};
スプレット演算子はobjectにも使える
配列
const x = [1,2,3];
console.log(...x); // 1 2 3
object
const x = { x: 1 };
const y = { y: 2 };
console.log({ ...x, ...y }); // {x: 1, y: 2}
objectの分割代入で変数名を指定できる
const user = { id: "hoge" };
const { id } = user;
const { id: no } = user;
console.log(id, no); // hoge hoge
クラスのコンストラクタは引数にアクセス修飾子をつけることでプロパティ が定義される
class User {
id: number;
constructor(id: number) {
this.id = id;
}
}
と
class User {
constructor(public id: number) {}
}
は同義である
関数型のインターフェース
interface Hoge {
(x: string): string;
}
const hoge: Hoge = (x: string): string => x;
と
type Hoge = (x: string) => string;
const hoge: Hoge = (x: string): string => x;
は同義である
交差型
class、interface、object型を交差すると結合した型になる
type Hoge = {
x: string;
};
type Fuga = {
y: string;
};
let hogeAndFuga: Hoge & Fuga = { x: "x", y: "y" };
union型を交差すると共通部分の型になる
type Hoge = number | boolean;
type Fuga = number | string;
let x: Hoge & Fuga = 1;
// x = "1"; エラー
// x = true; エラー
型ガード
typeof、instanceof、inのいずれかを使う
typeofはプリミティブ型で使う
const x: number | string = 1;
if (typeof x == "string") {
// string
} else {
// number
}
ユーザー定義クラスではinstanceofまたはinを使う
instanceof
class Hoge {};
class Fuga {};
const x: Hoge | Fuga = new Hoge();
if (x instanceof Hoge) {
// Hoge
} else {
// Fuga
}
in
class Hoge {
myfunc() {}
}
class Fuga {}
const x: Hoge | Fuga = new Hoge();
if ("myfunc" in x) {
// Hoge
} else {
// Fuga
}
また、インタフェースにはinstanceofが使えない。回避策としてリテラル型のプロパティを定義して使用することができる
interface Hoge {
kind: "hoge";
}
interface Fuga {
kind: "fuga";
}
let x: Hoge | Fuga = { kind: "hoge" };
if (x.kind == "hoge") {
// Hoge
} else {
// Fuga
}
型キャストの書き方
let y = x as Hoge;
と
let y = <Hoge>x;
は同義である
インデックス型
型は決まっているがキー名が決まってないプロパティを定義することができる
class Hoge {
[key: string]: number;
}
const hoge: Hoge = {
one: 1,
two: 2,
three: 3,
};
メソッドや関数をオーバーロードできる
class Hoge {
fuga(x: string): string;
fuga(x: number): number;
fuga(x: number | string) {
return x;
}
}
ジェネリックに制約をつける
extends
を使う
const check = <T extends number | string>(x: T, y: T): boolean => {
return x == y;
}
keyof
でオブジェクトのプロパティに存在するという制約をつけることができる
const hoge = <T extends object, U extends keyof T>(obj: T, k: U) => {
return obj[k];
};
hoge({ id: 1 }, "id")
Utility Types
Partial以外にも色々ある
Discussion