Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TSConfigからTypeScriptの世界を覗く

 TSConfigからTypeScriptの世界を覗く

Avatar for light-planck

light-planck

May 23, 2025
Tweet

Other Decks in Programming

Transcript

  1. TSConfig との出会い ts-jest のESM サポートの設定を見直すときに初めてTSConfig を変更した ts-jest はTypeScript のコードをJest でテストするためのツール

    module オプションを CommonJS から ESNext に変更 tsconfig.json の最終更新が3 年前 メンテナンスしたい 最初はオプションが多くて何がなんだか分からない 調べていくうちにTypeScript の知識が付いた この発表の原点はこの経験にある。
  2. TypeScript の処理の流れ true false (デフォルト) .ts TypeScript compiler noEmit? 型検査のみ実行

    型検査 エラーあり エラーなし true false (デフォルト) 型エラー? noEmitOnError? トランスパイル 出力なし .js
  3. TSConfig の全体像 tsconfig.json で設定可能なトップレベルのプロパティは以下の通り。 compilerOptions がTSConfig のオプションの大半を占める。 // tsconfig.json {

    "files": ["src/main.ts"], // tsc が対象とするファイル "include": ["src/**/*"], // tsc が対象とするファイル(ワイルドカードでも指定可) "exclude": ["node_modules"], // include の対象ファイルのうち、除外したいファイル "extends": "./configs/base", // 別のTSConfig ファイルの継承 "references": [], // Project References の設定 "watchOptions": {}, // `tsc --watch` のときの設定 "typeAcquisition": {}, // JavaScript の型情報を取得するための設定 // コンパイラの挙動を規定するための設定 "compilerOptions": {} }
  4. 主要なオプション target , module , strict を理解すれば、 tsconfig.json をざっくり読める。 また、これら3

    つのオプションを知れば、TypeScript の理解が深まる。 target => トランスパイル module => モジュールシステム strict => 型システム 以降では target と strict のうちの一つである strictFunctionTypes を見ていくことで、 トランスパイルと型システムというTypeScript の核心に接近したい。 ※ 主要かどうかの判断は筆者の主観です。
  5. target カテゴリ: Language and Environment target はTypeScript をECMAScript のどのバージョンにトランスパイルかを指定するためのオプション。 設定可能な値は

    ES3 , ES5 , ES6/ES2015 , ES2016 , …, ES2024 , ESNext がある。デフォルトは ES5 。 ESNext はTypeScript がサポートしている最新のECMAScript のバージョンになる。 TypeScript のバージョンを上げたら変わる可能性があるので注意が必要。
  6. target TypeScript はトランスパイル時に以下のことを行う。 型情報の削除 型注釈・型エイリアス・interface 宣言 target に対応したECMAScript の構文変換 アロー関数・テンプレートリテラル・let/const

    宣言・分割代入, … ただし、JavaScript のAPI の変換は行わない。 (ポリフィルの責務) Array.prototype.includes() Map や Set などのデータ構造 など。
  7. target ES2016 ES5 (Downleveling ) // TypeScript const greet =

    (name: string): string => { return `Hello, ${name}!`; }; const isIncluded = [1, 2, 3].includes(1); // JavaScript (ES2016) const greet = (name) => { return `Hello, ${name}!`; }; const isIncluded = [1, 2, 3].includes(1); // JavaScript (ES5) var greet = function (name) { return "Hello, ".concat(name, "!"); }; var isIncluded = [1, 2, 3].includes(1); // includes はES5 に対応していない
  8. strict カテゴリ: Type Checking strict オプションは厳密に型検査したい場合に推奨されるオプションを全て有効にする。 2025 年5 月現在では以下のオプションが有効になる。 alwaysStrict

    (トランスパイルしたJS に "use strict; を追加) strictNullChecks (null とundefined の厳格なチェック) strictBindCallApply ( bind 、 call 、 apply の厳格な型チェック) strictBuiltinIteratorReturns (組み込みイテレータの戻り値チェック) strictFunctionTypes (関数型の厳格なチェック) strictPropertyInitialization (クラスプロパティの初期化チェック) noImplicitAny (暗黙的な any 型を禁止) noImplicitThis (暗黙的な this の型付けを禁止) useUnknownInCatchVariables (catch 節での unknown 型の使用)
  9. 構造的型付け(Structural typing ) TypeScript は型の互換性・等価性をオブジェクトの構造によって決定する。 これを構造的型付けと言う。 (Go などもこれに当たる) 構造的型付けの他には名前的型付けがあり、型の名前で互換性を決定する。 (Java,

    PHP など) 上記の例ではAnimal とHuman で名前が異なるのでコンパイルエラーになる。 interface Animal { name: string; } interface Human { name: string; } const human: Human = { name: " 人間", }; const animal: Animal = human; // 構造が同じなので、コンパイルエラーにならない
  10. 部分型(Subtyping ) ある型Sub が別の型Super に包含されるような階層構造のとき、型Sub をサブタイプ(部分型) 、型Super をス ーパータイプと呼ぶ。 このとき、Sub

    はSuper に互換性がある。Sub はSuper に置き換えられると言い換えてもよい。 型Sub が型Super の部分型であるとき、 Sub <: Super と書く。 Human はAnimal のサブタイプであり、Animal に対して互換性を持つので、以下のコードはコンパイルエラー にならない。その逆はコンパイラエラーとなる。 const human: Human = new Human(); const animal: Animal = human;
  11. 構造的部分型(Structural subtype ) 構造的型付けにおいてサブタイプである条件は、ある別の型の全てのプロパティとメソッドを安全に呼び出せ るかによって決定する。つまり構造に着目している。 以下の例では、Human はAnimal の全てのプロパティとメソッドを安全に呼び出せるため、Human はAnimal の

    サブタイプ(部分型) 、Animal はHuman のスーパータイプである。 // スーパータイプ interface Animal { name: string; } // サブタイプ interface Human { name: string; read: () => void; } let human: Human = { name: " 人間", read: () => console.log(" 読んだ"), }; const animal: Animal = human; // 互換性があるので代入可能 human = { name: " ねこ" }; // Property 'read' is missing in type '{ name: string; }' but required in type 'Human'.
  12. 変性(Variance ) 変性はジェネリクス型において型パラメータのサブタイプ関係とジェネリクス型のサブタイプ関係を定義する 概念。 ジェネリクス型とは型引数を受け取り、別の型を構成する型。 Sub とSuper の配列の変性、つまり Array<Sub> と

    Array<Super> のサブタイプ関係はTypeScript では Sub <: Super , Array<Sub> <: Array<Super> と定義されている。 サブタイプ関係の方向が一致しており、これを共変と言う。逆に方向が反転する場合は反変と言う。 interface Animal { name: string; } interface Human { name: string; read: () => void; } const humans: Human[] = [ { name: " 人間1", read: () => {} }, { name: " 人間2", read: () => {} }, ]; const animals: Animal[] = humans;
  13. strictFunctionTypes 、再び TypeScript は strictFunctionTypes が false のとき、型引数の変性を共変・反変のどちらも許可する。これ を双変と呼ぶ。 しかし双変は以下のような場合があるため、危険である。

    より多くのものを扱える関数は、より少ないものを扱う関数に置き換えられない。 // 共変 // H <: A // HumanFunction(H) <: AnimalFunction(A) const humanFunction1: HumanFunction = (human: Human) => console.log(human.read()); const animalFunction1: AnimalFunction = humanFunction1; animalFunction1({ name: " ねこ" }); // read を呼び出そうとしている! // 反変 // H <: A // AnimalFunction(A) <: HumanFunction(H) const animalFunction2: AnimalFunction = (animal: Animal) => console.log(animal.name); const humanFunction2: HumanFunction = animalFunction2; humanFunction2({ name: " 人間", read: () => {} }); // 特に問題はない
  14. TSConfig のメンテナンスについて 最後に tsconfig.json を変更したのはいつですか? 本セッションが tsconfig.json を見直すきっかけになったら嬉しい。 ポイント strict

    が true になっているか ECMAScript のバージョン Recommended なオプションを有効にしているか 最近のオプションの把握
  15. ECMAScript のバージョン target , lib が現在最新の ES2024 / ESNext になっているか?

    (明確な理由があって最新にしていない場合は別) lib はJavaScript のAPI やDOM の型情報を指定するオプション。これが古いとAPI の型も古いままになってし まう。
  16. Recommended なオプションを有効にしているか 公式が推奨しているオプション。 ただしTSConfig Reference から「Recommended 」でページ内検索して見つける必要がある。 大半はデフォルトで有効・ strict で有効なので、それ以外のオプションは以下がある。

    exactOptionalPropertyTypes オプショナルプロパティにundefined の明示的代入を禁止する設定 esModuleInterop CommonJS とES6 モジュール間の互換性を改善する設定 skipLibCheck 型定義ファイル(.d.ts )の型チェックをスキップして高速化する設定
  17. 最近のオプションの把握 例えばV5.8 で追加されたオプションに erasableSyntaxOnly がある。カテゴリは Interop Constraints 。 Node.js 23.6

    では、 --experimental-strip-types モードでTypeScript ファイルを直接実行することができ る。 (Experimental ) ただし、TypeScript 固有の構文が実行時セマンティクスを持たなければならない。 (型注釈のような簡単な消去 することができるものに限る) enum 宣言 実行時コードを含むnamespace やmodule クラスのパラメータープロパティ CommonJS のimport = やexport = 代入
  18. 参考文献 鈴木僚太『プロを目指す人のためのTypeScript 入門』技術評論社, 2022. 「TypeScript Documentation 」, https://www.typescriptlang.org/docs/ 「Structural type

    system 」, https://en.wikipedia.org/wiki/structural_type_system 「Covariance and contravariance (computer science) 」, https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) 「サバイバルTypeScript 」, https://typescriptbook.jp/
  19. まとめ TSConfig は多数存在するが、階層やカテゴリを意識すると見通しが良くなる target トランスパイル時に型情報の削除と構文の変換を行う JavaScript のAPI は変換しない strictFunctionTypes 関数の型引数を双変から反変に変更する

    TSConfig のメンテナンス観点 strict が true になっているか ECMAScript のバージョンが最新か Recommended なオプションを有効にしているか 最近のオプションの把握