項目72 TypeScriptの独自機能の使用を避け、ECMAScriptの機能を使う
JavaScriptとTypeScriptの開発は以下のように行われている
TC39がランタイムを定義、TypeScriptはチームは型空間の革新のみを行う 上記の取り決め以前のTypeScriptには独自機能があり、なるべく使用を避けるようにする
独自機能
enum
TypeScriptのenumは何種類かあり、それぞれ挙動が微妙に異なる
数値のenum
number型を代入可能なので、あまり安全ではない
文字列のenum
TypeScriptの他の方のように構造的型付けがされていない
code:ts
enum Flavor {
Vanilla = 'vanilla',
Chocolate = 'chocolate',
Strawberry = 'strawberry',
}
let favoriteFlavor = Flavor.Chocolate; // 型はFlavor
favoriteFlavor = 'strawberry';
const enum
通常のenum異なり、const enumは実行時に消えてしまう
preserveConstEnumsフラグを設定した状態でのconst enum
通常のenumのようにconst enumに対応する実行時のコードが生成される
基本的には文字列のリテラル型で対応できるので、極力enumは使わないようにする
パラメータプロパティ
TypeScriptにはパラメータプロパティ(プロパティ昇格)という機能があるが、これには注意すべき点がある
パラメータプロパティは、JavaScriptへのコンパイル時にコードが書き足される数少ない構文
パタメータはコンパイル後のコードのみで使用されるため、本のコードでは未使用のパラメータが存在するように見える
パタメータプロパティと非パラメータプロパティを混在させると、クラス設計の見通しが悪くなる
パラメータプロパティが存在することで、可読性が悪くなるパターン
code:ts
class Person {
first: string;
last: string;
constructor(public name: string) {
}
}
namespaceとトリプルスラッシュインポート
ECMAScript 2015以前のJavaScriptには公式のモジュールシステムが存在しておらず、TypeScirptは独自のモジュールシステムを開発してい対応していた。それがmoduleキーワードとトリプルスラッシュインポート
ECMA 2015でモジュールシステムが追加されると、moduleのシノニムとしてnamespaceを追加した
これらを使ったインポートは極力行わない
code:ts
namespace foo {
export function bar() {}
}
/// <reference path="other.ts"/>
foo.bar();
実験的デコレーター
TypeScriptは2015年に、Angularをサポートするために、デコレータのドラフト案の実験的サポートを追加し、--experimentalDecoratorsフラグを使う その後2023年にECMAScriptの標準デコレータが追加された
基本的にはexperimentalDecoratorsフラグはオフにし、標準の機能を使う
メンバーのアクセス修飾子
歴史的に、JavaScriptにはクラスのプロパティやメソッドをプライベートにする方法がなかった
アンダースコアの接頭辞をつけたものはプライベートとする、といったような方法で回避していた
TypeScriptは独自機能としてpublic, protected,privateのアクセス修飾子を追加した
ただ、privateは型システムの機能なので、JavaScriptにコンパイルすると消えてしまう
ES2020からは、プライベートフィールドが正式にサポートされたので、TypeScriptでプライベートフィールドを定義する際もこの構文を使うと安全
クラスのプロパティに接頭辞#を付ける
code:ts
class PasswordChecker {
constructor(passwordHash: number) {
this.#passwordHash = passwordHash;
}
checkPassword(password: string) {
return hash(password) === this.#passwordHash;
}
}
const checker = new PasswordChecker(hash('s3cret'));
checker.#passwordHash
// ~~~~~~~~~~~~~ Property '#passwordHash' is not accessible outside class
// 'PasswordChecker' because it has a private identifier.
// プロパティ '#passwordHash' には private 識別子が指定されている
// ため、クラス 'PasswordChecker' の外部ではアクセスできません。
checker.checkPassword('secret'); // falseを返す
checker.checkPassword('s3cret'); // trueを返す