Typescript学び直し
パッケージマネージャ
NPM/NPX
- package.json
- アプリケーション情報
- インストールしたモジュールのバージョンの依存関係
- package-lock.json(yarn.json)
- package.jsonとの利用モジュールの依存関係
- モジュールの存在URL
- node_modules
- モジュール本体
- ここは.gitignoreにいれる
※ npxはnode_modulesにインストールしたモジュールを実行する事ができる
内部的には npm exec
を実行しているだけ
宣言
var
: 再宣言できる。使わない
- 他にもグローバル変数として定義された場合、 window
オブジェクトのプロパティとして定義されるため、既存のプロパティを上書きする可能性がある。
- 変数の巻き上げでエラー起きる(宣言前の変数を参照してもReference Error
が起きない)
- let
,const
も変数巻き上げは起きるが、undifined
で再代入が
let
: 再宣言できない。再代入はできる
const
: 再宣言できない。再代入できない。
極力const
を使う。 for文とかしかletを使わないくらいのほうがいい。
読み手の負荷を下げることができる
ただし、constを使っても、
Array(配列), Object(オブジェクト)は参照型のデータなので、
変更ができる。(再代入はできない)
const myArr = [1, 2]
myArr[1] = 10
console.log(myArr) // [1, 10]
配列・オブジェクトを変更不可にする方法は別途用意されている
-
配列・オブジェクト共通
as const
を使う。const assertionという。 -
配列のみ。
読み取り専用の型を使う。
readonly T[]
,ReadOnlyArray<T>
, 記法はどっちでもいい
当たり前だけど、コンパイル時にエラーが出るだけで、
エラーを無視してjsを実行すれば代入はできてしまう。 -
TS上で読み取り専用配列に代入したい場合
型アサーションを使って、通常の配列に戻せば代入できる。(あまり使わないほうがいい) -
readonly
とas const
の違い
readonly
はオブジェクトのプロパティごとにつけられる。as const
はすべてかつ再帰的。
型アサーション(type assertion)
value as T
, <T> value
のどちらかで実行できる。
<>
はJSXでも使ってるのでas
を使ったほうが良さげ
TSにおけるType Assertionはキャストとは異なり、実行時に値の型を変換しているわけでないので、キャストと呼ばない。
型アサーションと型アノテーション(型注釈)という呼び分け。
制御フロー分析と型ガード
型アサーションを利用する場合、バグを産まないように、これらを利用する
- ユニオン型の曖昧さがよくあるケース
func doSomething(month : string | number) {
month.padStart(2, "0"); // 月を2桁にする関数
}
を定義した場合、このままだとnumber型を受けた際の処理が考慮できていない
- 制御フロー分析=>「曖昧さが存在する場合、事前に型チェックをする」こと
func doSomething(month : string | number) {
if typeof month === "string") {
console.log(month.padStart(2, "0")); // 月を2桁にする関数
return; // early return
}
// elseを書かずにealry returnのほうがいい
// TSでは、このコードブロックまでたどりついた際にはmonthをnumber型と推論してくれるので
// number型のときだけ使えるメソッドを利用できる
console.log(mont.toFixed());
}
※ null
はi type of value === "object"
がtrue
を返すので、 null
が混在する可能性がある制御フローでは、value != null
をand条件で指定する
-
制御フロー分析
ifやforループなどの制御フローを分析し、コードが実行されるタイミングでの型の可能性を判断すること -
型ガード
-
typeof
演算子を使って、 確認する(これはjsの演算子なので"object"である、までしか判定できない) -
instanceof
演算子をつかって、クラスオブジェクトをより詳細まで判定する場合はこちら
function getMonth(date: string | Date) { if (date instanceof Date) { console.log(date.getMonth() + 1); } }
-
in
演算子をつかう。特定のクラスのインスタンスであることを明示せず、オブジェクトが特定のプロパティをもつかを絞り込める。(インターフェース)
-
interface Wizard {
castMagic(): void;
}
interface SwordMan {
slashSword(): void;
}
function attack(player: Wizard | SwordMan) {
if ("castMagic" in player) { // これもクラスオブジェクトでしか使えない
player.castMagic();
} else {
player.slashSword();
}
}
- アサーション関数を作る
ガード関数との違いは、例外を投げる
function isDuck(animal: Animal): asserts animal is Duck { // 戻りの型が asserts arg is T になるのがミソ
if (walksLikeDuck(animal)) {
if (quacksLikeDuck(animal)) {
return;
}
}
throw new Error("YOU ARE A FROG!!!");
}
asserts arg is T
の部分をType predicateという。
これは戻り値がboolean型の関数に対して利用できる。
trueを返す時のifのブロックの中では当該の変数をT型として解釈できるようになる
function isDuck(animal: Animal): animal is Duck {
return animal instanceof Duck; // instanceof ではクラスオブジェクトしか判定できない
}
if (isDuck(animal)) {
animal.quacks(); // このブロックでは変数animalはDuck型であることがType predictで解釈される
// ...
}
型ガードの変数代入。変数スコープを広くしたいときはこれ
function getMonth(date: string | Date) {
const isDate = date instanceof Date;
if (isDate) {
console.log(date.getMonth() + 1);
}
// 後続の処理でもisDateを利用できる、という書き方
}
変数スコープ
-
グローバルスコープ
- ブラウザでは
window
オブジェクトがグローバルオブジェクト - グローバル変数はグローバルオブジェクトのプロパティになる
-
Date
クラス,console
オブヘクトなどの組み込みAPIはもれなくこれ。 - グッローバルオブジェクトへのアクセスは
window
を省略できる
-
- ローカルスコープ以外で
var
を使用するとグローバル変数になる -
var
は関数スコープで定義されてしまうので、ブロックスコープで値を更新すると、影響を受ける
- ブラウザでは
-
関数スコープ
- 関数内で参照できる
-
レキシカルスコープ
- 関数の中から見て、参照できる関数の外の変数
-
ブロックスコープ
- ブレース
{}
で囲まれた範囲
- ブレース
-
意図しないグローバル変数の代入
- jsでは、関数内にて宣言しない変数に代入した場合、グローバル変数を新規に作ってしまう
- TSではこれは起きない。
変数宣言時の型推論について
TSではlet, constでの変数宣言時、型注釈をつけなくても 初期値を代入してあれば、
型を推論してくれる
let x = 1;
x = "hello"; // Type 'string' is not assignable to type 'numer'
型
プリミティブ型
-
イミュータブルな特性を持つ
-
一方オブジェクト型(参照型)は、ミュータブル
-
プリミティブ型はプロパティを持たない。
null
,undifined
とか -
ただし、stringや数値はプロパティを持ったオブジェクトとしても扱える。これがJSの特徴。
-オートボクシングという。プリミティブ型をオブジェクト型に自動変換する
ボックス化について
JAVAなどとおんなじような思想で、JSにも、プリミティブ型に対するラッパーオブジェクトがある。
ラッパーオブジェクトをnewで作ると、ボックス化される。が、上述の通り、自動ボックス化されるので、
明示的にやる必要もない
プリミティブ型 | ラッパーオブジェクト |
---|---|
boolean | Boolean |
number | Number |
string | String |
symbol | Symbol |
bigint | BigInt |
undefined | なし |
null | なし |
※ symbol型: 一意で不変の値 |
プリミティブ型とラッパーオブジェクト
- 型注釈にラッパーオブジェクトは利用できるが、対応するプリミティブ型への代入できない。
- ラッパーオブジェクト型は演算子が使えない。
- ラッパーオブジェクトはインターフェースを満たせば他のオブジェクトも渡せる
const myboolean = {
valueOf(): boolean { // valueOfのインターフェースをもっていれば`Boolean`オブジェクトの代替となる
return true;
},
};
const bool: Boolean = myboolean;
- ラッパーオブジェクトを型注釈に使う利点はない。
型強制(type coercion)
javascriptの話。暗黙の型変換 = 型強制
左辺・右辺どちらかに文字列型があり、+
演算子が発生したときのみ、文字列としての加算を行う。
他の-, *, /
などはnumber型に変換する
console.log(1 + "1"); // 11
console.log("1" + 1); // 11
console.log("1" - 1); // 0
console.log(1 - "1"); // 0
console.log("1" - "1"); // 0
リテラル型の細かなTIPS
数値リテラル
-
.
で少数点が表現できる
0.1 === .1 // true
5.0 === 5. // true
- 10進数以外の対応
0b1010 // 2進数
0o755 // 8進数
0xfff // 16進数
- 数値の区切り(numeric separators)
100_000_000 // 1億
// 小数点の表現は使えない
0_000_1 // これは使えない
_000_1 // これも使えない
100_._1 // これも使えない
- 数値リテラルのプロパティを参照する場合
-
()
で囲む -
..
で参照する
(5).toString();
5..toString();
-
NaN
、とInfinity
NaN
はnot-a-number。処理の結果数値にならない場合に返る。
const price = parseInt("百円");
console.log(price);
Number.isNaN
メソッドで判定する
const price = parseInt("百円");
if (Number.isNaN(price)) {
console.log("数値化できません");
}
NaN
の比較は常にfalse
が返る。
NaN === NaN; // false
Nan == Nan; // fale
この性質を利用するとisNaNメソッドがかける
const isNaN: (value) => boolean{
rerutn value !== value
}
Infinity
が0で割ったときに返る。
TSでもエラーとしては検出しない。JSがInfinityを返す、という仕様のため、
- 少数計算は誤差が出る
循環小数を丸めたことによる丸め誤差である。
桁数がわかっているときは、整数に桁上げした後、計算し、戻す、というやり方がいい。
正確に計算したければdecimal
をつかう
0.1 + 0.2 === 0.3; //=> false
BigInt関数
const x: bigint = 100n;
const x: bigint = BigInt("1000000000000000")
const x: bigint = BigInt("1_000") // これは渡せない
number
とbigint
では演算できないので、bigint
関数で表現幅の広い方に合わせる
2n + 3; // -> エラー
2n + BigInt(3); //=> 5n
javascriptではNaN
, Infinity
, -Infinity
という特殊な値がある
- const nan: number = 0/ 0
- inf: number = 1/0
- minusInf: number = -1/0
boolean型
- 空文字列(
''
)、数値の0
、undefined
、null
はif文においてはfalseとして扱われる -
true
,false
をつかう - 型の変換
-
Boolean(arg: Any)
でboolean型に変更できる -
!!
で、その型のゼロ値であるか、を判断するboolean型に変換できる
-
const a: number = 1
console.log(a) // 1
console.log(!a) // false -> number型のゼロ値である`0`ではないので falseが返る
console.log(!!a) // true -> boolean型の`!a`でfalseのboolean型になって `!`でtrueになる。(つまり当該型のゼロ値判定後変数になる)
文字列型
-
""
,''
はどちらでもいい -
``
(バッククォート)はテンプレートリテラル(フォーマット文)、${式}で値を挿入できる - 利用順序のおすすめ
- 基本的に"を使用する
- 文字列の中に"が含まれる場合は'を使用する
- 文字列展開する必要があるときは`を使用する
null型とundefined型
- nullはリテラルがある
const x: null = null;
- undefinedはリテラルがない。グローバル定数的なもの。プリミティブな値。
const x: undefined = undefined;
-
以下のようなときに発生する
- 変数に値がセットされていない
- 戻り値が無い関数、オブジェクトに存在しないプロパティにアクセス
- 配列に存在しないインデックスでアクセス
-
違い
- undefinedは「値が代入されていないため、値がない」、nullは「代入すべき値が存在しないため、値がない」
- nullは明示的に使用した場合しか発生しない
-
typeof
演算子の扱いが異なる
-
実用的な使い型は
Union
型、Optional
型で使う -
undefine型 == 予期せぬ空値、 null型 == 明示的な空値
- しかし、Tsではundefine型に統一すること後コーディングガイドラインには記載がある
typeof undefined; // "undefined"
typeof null // "object"
- JSONの扱い
-
undefined
は未定義扱いなので、プロパティが存在しない、と扱う -
null
は該当する値がないので、プロパティが存在する、と扱う
-
console.log(JSON.stringify({ foo: undefined }));
// =>{}
console.log(JSON.stringify({ foo: null }));
// => {"foo": null}
- 値の比較
const a: null = null
console.log(a === undefined); // false
console.log(a == undefined); // true
console.log(a === null); // ture
console.log(a == null); // true
const b: undefined = undefined
console.log(b === undefined); //true
console.log(b == undefined); // true
シンボル型
シンボルはシンボル名が同じであっても、初期化した場所が違うとfalseになる。
同一の参照である必要がある。
JS本体の開発用に導入されているので、使わない。
const s1 = Symbol("foo");
const s2 = Symbol("foo");
console.log(s1 === s1); // true
console.log(s1 === s2); // false -> tsではコンパイルエラー
リテラル型
特定の値のみを代入可能にする型。
let x: 1 = 1;
x = 1; // ok
x = 100; // '100' is not assignable to type '1'
つかえるのは以下のプリミティブ型
const isTrue: true = true;
const num: 123 = 123;
const str: "foo" = "foo";
使い所
ユニオン型と組み合わせ、マジックナンバー、ステートの表現に使う
let num: 1 | 2 | 3 = 1;
Any型
何でもOK(型チェックをパスさせる)
暗黙のany
型を省略してコンテキストから型が推論できない時、TypeScriptは暗黙的に型をany型として扱う。
バグの原因にはなりうる。
tsconfig.json のnoImplicitAny: trueが推奨(strict: trueでも有効になる)
オブジェクト
プリミティブ型以外は参照を返す。
- リテラル
// 空っぽのオブジェクトを生成
const object = {};
// プロパティを指定しながらオブジェクトを生成
const person = { name: "Bob", age: 25 };
-
new
演算子を使っても作れるが、上のほうがスマート
const person = new Object();
person.name = "Bob";
person.age = 25;
- jsではオブジェクトのプロパティにメソッドを渡せる。
- jsはオブジェクトのプロパティで値と、メソッドを分けていないので、値を設定しているプロパティ似関数を代入する、その逆もできてしまう。
const object = {
// キーと値に分けて書いたメソッド定義
printHello1: function () {
console.log("Hello");
},
// 短い構文を用いたメソッド定義
printHello2() {
console.log("Hello");
},
};
型エイリアス
type
キーワードを使う
型エイリアスは同じ型を再利用したいときに使うと便利です。型の定義が一箇所になるため、保守性が向上します。
また、型に名前を与えることで可読性が上がる場合があります。
type StringOrNumber = string | number;
// プリミティブ型
type Str = string;
// リテラル型
type OK = 200;
// 配列型
type Numbers = number[];
// オブジェクト型
type UserObject = { id: number; name: string };
// ユニオン型
type NumberOrNull = number | null;
// 関数型
type CallbackFunction = (value: string) => boolean;
型注釈
オブジェクト
;
で定義する。
let box: {
width: number;
height: number;
};
box = { width: 1080, height: 720 };
- 型エイリアスでもできる
// 型エイリアス
type Box = { width: number; height: number };
let box: Box = { width: 1080, height: 720 };
// ^^^型注釈
メソッドの型注釈
let calculator: {
sum(x: number, y: number): number;
};
calculator = {
sum(x, y) {
return x + y;
},
};
// 関数型の書き方でもOK
let calculator: {
sum: (x: number, y: number) => number;
};
⇢こっちの書き方のほうがいい。
なぜなら、引数の共変性を制限するtsconfig.json
のstrictFunctipnTypes: true
のオプションに乗っかれるから
引数の双変性
関数型の変数に対して、代入を行う際に、
その関数がとりうる引数の型の範囲を拡張・縮小をおこなえる性質
let func: (x: number | null) => any;
という型をもつfuncを定義すると。
funcには以下のような代入が可能
func = (n: number | null) => {}; // OK
func = (n: number | null | undefined) => {}; // OK
func = (n: number) => {}; // OK
範囲を狭めることを引数の共変性といい
範囲を広めることを引数の反変性という
2つを合わせて引数の双変性という
共変性は型安全から外れるので、使いたくないので、
tsconfig.json
のstrictFunctipnTypes: true
をいれる。
ただし、この性質はメソッド型の記述ではチェックされない。
なのでオブジェクトにメソッドを定義する場合も関数型のほうがいい
interface Obj {
// メソッド型
method(n: number | null): any;
}
const obj: Obj = {
method: (n: number) => {}, // チェックされない
};
interface Obj {
// 関数型
method: (n: number | null) => any;
}
const obj: Obj = {
method: (n: number) => {}, // チェックが働く
};
※ 関数型 = :
の後ろにメソッドのシグネチャを書く。型が関数であるというイメージ
オブジェクトの型推論
型を定義しなくても、初期リテラルから、推論をしてくれる
Record<Keys, Type>
連想配列を定義するときはこうする。
オブジェクト型との違い。 あくまで、キーは未定の値を取るが、key,valueには型がある
type StringNumber = Record<string, number>;
const value: StringNumber = { a: 1, b: 2, c: 3 };
//こう書くと、要素が増えていくものを想定している
value.d = 4
type StringNumber = Record<"a"| "b" | "c", number>;
const value: StringNumber = { a: 1, b: 2, c: 3 };
//こう書くと、通常のオブジェクトの定義と一緒
value.d = 4 // これはコンパイルエラー
// つまり
type StingNumber = {
"a": number;
"b": number;
"c": mumber;
}
と一緒
つまり、前者の方法での利用、 インデックス型を定義する1つの方法
他のインデックス型
type IndexKey: {
[K: string]: number;
};
type IndexKey: {
[key: string]: number;
};
tsconfig.json
のnoUncheckedIndexedAccess
を有効にすると、
インデックス型のプロパティを代入する先の変数は当該型とundifined型とのUnion型となる
Mapped Types
インデックス型と異なり、キーは特定の値のみしか設定できない。
普通のオブジェクト型はこれに該当する。
- キーをちゃんと定義する(普通のオブジェクト型)
type MyMapp = {a: string; b:string}
-
key in Union
を使う
type MyMapKey = "a" | "b";
type MyMapp = {
[key in MyMapKey]: string
}
- 2の例が
Readonly<T>
- 内部的には各propertyにreadonly修飾子をつけている
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
- Mapped Typeでは追加のプロパティは定義できないので
- インターセクション型を使って型定義をかえる
type KeyValues = {
[K in string]: string;
};
type Name = {
name: string; // 追加のプロパティ
};
type KeyValuesAndName = KeyValues & Name;
keyof型演算子
keyofはオブジェクト型からプロパティ名を型として返す型演算子
type Book = {
title: string;
price: number;
rating: number;
};
type BookKey = keyof Book;
// 上は次と同じ意味になる
type BookKey = "title" | "price" | "rating";
インデックス型にkeyofを用いると、インデックスキーの型が返る。
type MapLike = { [K: string]: any };
type MapKeys = keyof MapLike; // string | number
↑ jsのMapオブジェクトはnumberをキーに指定しても、内部出来にはstring型で扱うので
myMap["0"]とmyMap[0]は等価なので、string | number
がインデックス型では返る
type MapLike = { [K: string]: any };
const myMap: MapLike = {
1: 1,
0: 2
}
console.log(myMap) //{ '0': 2, '1': 1 }
Mapped Typesにkeyofを用いる
type MapLike = { [K in "x" | "y" | "z"]: any };
type MapKeys = keyof MapLike;
プロパティを持たないオブジェクト型につかうとnever
型が帰る
type What = keyof {}; // never
any型に使うと、オブジェクトのkeyをとれる、string | number | symbol型が返る
typeof型演算子
typeofは変数から型を抽出する型演算子。
const point = { x: 135, y: 35 };
type Point = typeof point; // type Poiint = { x: number; y: number}
jsのtypeof演算子とは別
typeof演算子
値の型を返すが、javascriptなので、ユーザ定義型は識別できない。
typeof true; //=> "boolean"
typeof 0; //=> "number"
typeof "Hello World"; //=> "string"
typeof undefined; //=> "undefined"
typeof null; //=> "object" "null”がオブジェクトで返るのがミソ
typeof Symbol(); //=> "symbol"
typeof 1n; //=> "bigint"
typeof [1, 2, 3]; //=> "object"
typeof { a: 1, b: 2 }; //=> "object"
typeof (() => {}); //=> "function"
配列を判定する
typeof 演算子では配列はobject
型なので、
専用にArray.isArray()
メソッドがある
if (Array.isArray(n)) {
// n is any[]
}
unknown型
unknown型は型安全なany型
unknown
型の値は、具体的な型を持つ変数へ代入できない。
プロパティへのアクセス、メソッド呼び出しもできない
つまり、型を確定するまで何もできないようにしたいときに使う
※ unknown
型の変数自体には代入できる
let newMyNumber: unknown = 0;
newMyNumber = 1;
console.log(newMyNumber) // 1
let huga = newMyNumber // これはコンパイルエラー
unknown型を配列型に絞り込む
function isNumberArray(value: unknown): value is number[] {
if (!Array.isArray(value)) {
return false;
}
return value.every((e) => typeof e === "number"); // everyメソッドで要素の方まで確認する
}
uknown型をオブジェクト型へ絞り込む
-
typeof
ではobject
であることしか判別できない -
instanceof
はクラスじゃないので使えない
=>そんなときの考え方
- パターン①
これだとobject型であること検証していない。Email型であるかは確実ではない
type Email = {
from: string;
to: string;
title: string;
subject: string;
};
function isEmail(value: unknown): value is Email {
if (typeof value !== "object" || value === null) {
return false;
}
return true;
}
- パターン②
なので、プロパティのチェックもしてみようとするが、
valueにformというプロパティがあるか推論できないのでラーとなってしまう。
function isEmail(value: unknown): value is Email {
if (typeof value !== "object" || value === null) {
return false;
}
// 各プロパティのチェック
if (typeof value.from !== "string") { // valueにformというプロパティがあるか推論できないのでラエー
return false;
}
return true;
}
- パターン③
なので、型サーションを使いたい。
(value as T)
or(<T>value)
しかしas Emailだと、 インターセクション型を使って型を拡張されていた場合がすり抜ける。
function isEmail(value: unknown): value is Email {
if (typeof value !== "object" || value === null) {
return false;
}
// 各プロパティのチェック
const email = value as Email;
if (typeof email.from !== "string") {
return false;
}
return true; // Email & {"huga": string} という型でもtrueを返してしまう。
}
ので、より安全にチェックするときには `Record<Key of T, known>を使う。
function isEmail(value: unknown): value is Email {
if (typeof value !== "object" || value === null) {
return false;
}
// 型アサーションでvalueをEmail型に近づける
const email = value as Record<keyof Email, unknown>;
// 各プロパティのチェック
if (typeof email.from !== "string") {
return false;
}
if (typeof email.to !== "string") {
return false;
}
if (typeof email.title !== "string") {
return false;
}
return typeof email.subject === "string";
}
uknown型で型アサーションを突破する
// 異なる型は指定できないが
const str = "a";
const num = str as number;
// unknwonを経由すれば行ける
const num = str as uknown as number;
### useUnknownInCatchVariables
例外はunknwon型を明記することができるようになった
```ts
// case 1
try {
throw new Error();
} catch (err) {
// err = any
}
// case 2
try {
throw "This is an error!";
} catch (err: unknown) {
// err = unknown
}
// case 3
try {
throw undefined;
} catch (err: unknown) {
// err = unknown
}
プロトタイプベース
jsはプロトタイプベース。
クラスベースはクラスという設計図からインスタンスを生成するという考え方だが、
プロトタイプベースは既存のインスタンス(オブジェクト)をもとにあたらしいインスタンス(オブジェクト)をつくる、と言う考え方。
なので、jsにもクラスはあるが、オブジェクトの一種であり、クラスを特別扱いしない。
オブジェクトに対して、Object.create()
を実行することで、新しいオブジェクトを生成できる
const myObj = {name : "huga"}
const yourObjObject.create(myObj)
プロトタイプベースの継承
オブジェクトを作った後に足したい振る舞いを追加する。という形。extends
などのキーワードはない
const counter = {
count: 0,
countUp() {
this.count++;
},
};
const resettableCounter = Object.create(counter);
resettableCounter.reset = function () {
this.count = 0;
};
が、普通にクラスが使えるようになっている
class
で定義し、extends
で継承する
class ResettableCounter extends Counter {
reset() {
this.count = 0;
}
}
object, Object, {}の違い
一般的な型注釈と異なり、プリパティの型を指定せず、
ざっくり「オブジェクトであること」を型注釈することがある。
object型
object型では、オブジェクト型の値だけが代入できる。つまり、プリミティブ型は代入できない
Object型
Object型はインターフェース。vaueOf
などのプロパティを持つ値なら何でも代入できる。
Object型にはnullやundefinedを除くあらゆるプリミティブ型も代入できる。
(文字列型や数値型などのプリミティブ型もオートボックシングにより、
オブジェクトのプロパティをもつため。)
※こちらは利用非推奨。プリミティブ型が大有できてしまうため。object
型の利用を推奨
{}型
プロパティを持たないオブジェクトを表す。
プロパティを持つ値なら、null, undefinedを除く、全て代入できる
オブジェクトの分割代入
複数のプロパティを取り出す
const item = { price: 100 };
const { price } = item;
// 上は const price = item.price; と同等の処理
const obj = { a: 1, b: 2 };
const { a, b } = obj;
代入する変数名の指定
const color = { r: 0, g: 122, b: 204, a: 1 };
const { r: red, g: green, b: blue, a: alpha } = color;
console.log(green);
入れ子の分割代入
入れ子で指定すれば値を取り出せる
const continent = {
name: "北アメリカ",
us: {
name: "アメリカ合衆国",
capitalCity: "ワシントンD.C.",
},
};
const {
us: { name, capitalCity },
} = continent;
入れ子構造の分割代入と変数名の指定
const continent = {
name: "北アメリカ",
us: {
name: "アメリカ合衆国",
capitalCity: "ワシントンD.C.",
},
};
const {
name: continentName,
us: { name: countryName },
} = continent;
shorthand property
オブジェクトのキーと変数名が同一の場合に限り、以下のようにもかける
(多分つかわない)
type Wild = {
name: string;
no: number;
genre: string;
height: number;
weight: number;
};
const name = "pikachu";
const no = 25;
const genre = "mouse pokémon";
const height = 0.4;
const weight = 6.0;
const pikachu: Wild = {
name,
no,
genre,
height,
weight,
};