Help us understand the problem. What is going on with this article?

TypeScript 2.9 変更点

More than 1 year has passed since last update.

こんにちは。LINEの@uta_ttiです。

今日TypeScript 2.9がリリースされました。2.8のconditional typesと比べるとちょっと破壊力が足りない気もしますが、個人的に待っていた機能が入ったりしたので、紹介したいと思います。今回のアップデートではCLIやツール系の改善も多かったですが、言語自体の変更点だけ紹介します。詳しくは公式記事を参考してください。

もし内容(や日本語)などが間違ってたら教えてください。

import(...)式からの型import

import(...)はES modulesを動的に読み込む式になります。「式」という単語を使っていますが、実際import(...)は関数ではなく文法要素です。なのでtypeof importしても結果は出ませんし、第一級として扱うことも出来ません。

import(...)は現在ES仕様のステージ3であり、もうChromeなどでは実装されています。

TypeScriptでももちろんimport(...)自体は使えましたが、import(...)から型はimport出来なかったため、不自然にtop-level importを混ぜて使うしかありませんでした。

import { SomeType } from "./foo"

async function func() {
  let val: SomeType

  // ...

  val = (await import("./foo")).someValue
}

TypeScript 2.9 ではimport(...)が型情報も提供してくれるので、以下のように書けます。

async function main() {
  let val: import("./foo").SomeType

  // ...

  val = (await import("./foo")).someValue
}

JSON import

今まではJSONファイルはrequire(...)を使ってimportするしかなく、型はいつもanyでした。

let pkg = require("./package.json") // any
pkg.name // any

TypeScript 2.9からはJSONファイルにもimportを使えるようになり、型もつけてくれます。

import pkg from "./package.json"
pkg.name // string

keyof型の変更

今までkeyofは文字列ベースのキーにしか対応しませんでした。

interface X {
  str: any,
  1: any,
  [symbol]: any
}

keyof X // "str" | "1"

keyof any[] // "map" | "length" | ...

TypeScript 2.9からはnumberSymbolなどのキーにも対応し、Arrayの場合ちゃんとnumberもキーに含めてくれます。

interface X {
  str: any,
  1: any,
  [symbol]: any
}

keyof X // "str" | 1 | symbol

keyof any[] // number | "map" | "length" | ...

上の変更で、例えばkeyof Xの型の変数に"1"を入れるとエラーになります。破壊的な変更なので、対応が必要な場合があります。もし今までstringをとあるオブジェクトのキーの型として使ってたとしたら、stringの代わりに以下のように型を宣言して使うとよいです。

type ObjectKey = keyof any // instead of `string`

もしTypeScript 2.8までのように文字列ベースの動作が欲しい場合、compilerOptionskeyofStringsOnlyが新しく追加されましたので、これをtrueにすると以前と同じ動作でコンパイルしてくれます。

Tagged template literalsの型変数サポート

Tagged template literalsとは以下のようにとある関数をtemplate literalのtagとして使うものです。

func`hello${x}world${y}yay`;

上の式は実際以下のように書くのと同じです。

func(["hello", "world", "yay"], x, y);

Tagged template literalsについて詳しくは下のMDN文書を参考してください。

上の例で確認できるよう、tagged templateのtagは普通の関数です。TypeScriptでは関数に型変数を提供してpolymorphicな動作をさせることが出来ます。

function func<X, Y>(strs: TemplateStringsArray, x: X, y: Y)

func<string, number>([...], "hello", 10);

しかしtagged templateの場合それが出来ませんでした。

func<string, number>`hello${x}world${y}yay`; // syntax error
func`hello${x}world${y}yay`; // x: any, y: any

TypeScript 2.9では、tagged templateでも型変数を使えるようになりました。

func<string, number>`hello${x}world${y}yay`; // x: string, y: number

この機能を一番まっていたのはstyled-componentsではないかと思います。styled-componentsはcomponent定義でcustom propsも使えるようにしていますが、TypeScriptではcustom propsの型を提供することが出来ませんでした。

const MyH1 = styled.h1`
  color: ${props => props.customProp}
`; // type error, no `customProp` in props

それをTypeScript 2.9では以下のように提供できるようになります。

type MyH1Props = { customProp: string };

const MyH1 = styled.h1<MyH1Props>`
  color: ${props => props.customProp}
`;

実は上のコードはstyled-componentsに型バグがあるためまだ動きません。その修正をpull requestで出しておきました。

その他

その他、マイナーな変更点が何個かありますので、気になる方は公式記事を見てみてください。

utatti
Developer. Geek. Occasional indie creator.
https://noraesae.net
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away