コンテンツにスキップ

[TypeScript] 3.4

TypeScript3.4のリリース内容まとめ

Faster subsequent builds with the --incremental flag

SHOULD EASY

--incrementalオプションを使ってファイル単位でインクリメンタルビルドができるようになった。
ビルド時に作成されるtsconfig.tsbuildinfoを参照して、必要なビルドを判断する。

以下のファイル構成を含むプロジェクトを例にする。

  .
├──   main.ts
├──   sub.ts
└──   tsconfig.json
import { summ } from "./sub";

console.log(summ(39, 39));
export function summ(x: number, y: number) {
  return x + y + y;
}
{
  "compilerOptions": {
    // incremental build
    "incremental": true,

    "target": "es5",
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "out",

    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
  }
}

npx tscを実行するとtsconfig.tsbuildinfoが生成される。

tsconfig.tsbuildinfo
{
  "program": {
    "fileInfos": {
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.d.ts": {
        "version": "49ff9798f592c8b7e628fd881401e68810c1b3589ecd7a41b32b3c287374cde0",
        "signature": "49ff9798f592c8b7e628fd881401e68810c1b3589ecd7a41b32b3c287374cde0"
      },
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.es5.d.ts": {
        "version": "c8665e66018917580e71792b91022bcaf53fb946fab4aaf8dfb0738ed564db88",
        "signature": "c8665e66018917580e71792b91022bcaf53fb946fab4aaf8dfb0738ed564db88"
      },
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.dom.d.ts": {
        "version": "6994c583b66862deca24d7bbf77297d95b9d3da8160dbd9beef6b847cf7c1376",
        "signature": "6994c583b66862deca24d7bbf77297d95b9d3da8160dbd9beef6b847cf7c1376"
      },
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.webworker.importscripts.d.ts": {
        "version": "fe4e59403e34c7ff747abe4ff6abbc7718229556d7c1a5b93473fb53156c913b",
        "signature": "fe4e59403e34c7ff747abe4ff6abbc7718229556d7c1a5b93473fb53156c913b"
      },
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.scripthost.d.ts": {
        "version": "b9faa17292f17d2ad75e34fac77dd63a6403af1dba02d39cd0cbb9ffdf3de8b9",
        "signature": "b9faa17292f17d2ad75e34fac77dd63a6403af1dba02d39cd0cbb9ffdf3de8b9"
      },
      "c:/users/syoum/work/sandbox/typescript/release-note/sub.ts": {
        "version": "a642b6e0940719b7786b24d58aeb960c519b61d650b8bef5cb36f621a0189796",
        "signature": "0e2338170381690650d253ab294fb37c7ce39d2716d2d78723676a4b09c93457"
      },
      "c:/users/syoum/work/sandbox/typescript/release-note/main.ts": {
        "version": "dd8f4dcd7b8017a8965f69473ea700aacb154c5423793b174b873a60a7f53004",
        "signature": "f761c91419d0a89422a0004ef1a92929dd4d2d5e5c16758654d8b0467d1998c6"
      }
    },
    "options": {
      "incremental": true,
      "target": 1,
      "module": 1,
      "sourceMap": true,
      "outDir": "C:/Users/syoum/work/sandbox/typescript/release-note/out",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true,
      "configFilePath": "C:/Users/syoum/work/sandbox/typescript/release-note/tsconfig.json"
    },
    "referencedMap": {
      "c:/users/syoum/work/sandbox/typescript/release-note/main.ts": [
        "c:/users/syoum/work/sandbox/typescript/release-note/sub.ts"
      ]
    },
    "exportedModulesMap": {},
    "semanticDiagnosticsPerFile": [
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.d.ts",
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.es5.d.ts",
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.dom.d.ts",
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.webworker.importscripts.d.ts",
      "c:/users/syoum/work/sandbox/typescript/release-note/node_modules/typescript/lib/lib.scripthost.d.ts",
      "c:/users/syoum/work/sandbox/typescript/release-note/main.ts",
      "c:/users/syoum/work/sandbox/typescript/release-note/sub.ts"
    ]
  },
  "version": "3.4.5"
}

ファイルに変更が加わっているとversionが変わる。
関数名や引数名などが変わるとsignatureも変わるが、型変更だけでは変化がなかった。

Higher order type inference from generic functions

HAD BETTER EASY

ジェネリクス関数を引数にしてジェネリック関数を返す関数の戻り値(関数)に対して、型推論ができるようになった。

例としてA --(f)--> BB --(g)--> Cの合成関数A --(compose)--> Cを考える。

function compose<A, B, C>(f: (arg: A) => B, g: (arg: B) => C): (arg: A) => C {
  return (x) => g(f(x));
}

以下のコードにおけるmakeBoxedArrayT(arg: T) => Box<T[]>と推論されるべき。

interface Box<T> {
  value: T;
}

function makeArray<T>(x: T): T[] {
  return [x];
}

function makeBox<U>(value: U): Box<U> {
  return { value };
}

const makeBoxedArray = compose(makeArray, makeBox);

だが、TypeScript3.3以前ではそのように推論されない。
TypeScript3.4からは推論される。

Improvements for ReadonlyArray and readonly tuples

HAD BETTER EASY

readonlyのArrayをreadonly T[]のように表現できるようになった。
また、readonlyのTupleを使えるようになった。

readonlyなArray

バージョン 表現
v3.3以前 ReadonlyArray<T>
v3.4 readonly T[]

v3.3以前の表現はv3.4でも使える。

readonlyなTuple

const fruits: readonly [string, string] = ["apple", "orange"];
fruits[0] = "melon";  // 書き込みはできないのでエラー

Mapped TypesでArrayやTupleを指定したときのreadonly

v3.3以前のMapped Typesは、ArrayはTupleに対してreadonlyが有効にならない。

type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

// number[] とみなされる..
type B = MyReadonly<number[]>;

// [string, boolean] とみなされる..
type C = MyReadonly<[string, boolean]>;
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

// readonly number[] とみなされる
type B = MyReadonly<number[]>;

// readonly [string, boolean] とみなされる
type C = MyReadonly<[string, boolean]>;

const assertions

HAD BETTER EASY

式にas constをつけると、値が以下の型である場合に変更不可になる。

  • string
  • number
  • boolean
  • array
  • tuple
  • object
// const fixNumber = 10; と同じ
let fixNumber = 10 as const;

// const fixNums: readonly number[] = [10, 20, 30]; と同じ
const fixNums = [10, 20, 30] as const;

// const fixPair: readonly [number, string] = [100, "hundred"]; と同じ
const fixPair = [100, "hundred"] as const;

// 変更不可なObject
const fixObj = { id: 100, name: "hundred" } as const;

// fixObjNest.inner.id = 777 も不可
const fixObjNest = { inner: { id: 100 } } as const;

<const>を付けるでもOK。

// const fixNums = [10, 20, 30] as const; と同じ
const fixNums = <const>[10, 20, 30];

Type-checking for globalThis

NOT NECESSARY EASY

globalThisで各環境のグローバルオブジェクトを認識できるようになった。
ブラウザだとwindow、Node.jsだとglobalに相当する。

上記の出力は undefined になる

ちゃんと理由が分かっていない..。
main.jsはグローバルファイルではないからということだろうか..🤔