こんにちは。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からはnumber
やSymbol
などのキーにも対応し、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までのように文字列ベースの動作が欲しい場合、compilerOptions
にkeyofStringsOnly
が新しく追加されましたので、これを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で出しておきました。
その他
その他、マイナーな変更点が何個かありますので、気になる方は公式記事を見てみてください。