TypeScript 4.0 がリリースされました。新機能をピックアップし、試していきましょう。
Variadic Tuple Types
説明するのは、すごく難しい!!!
簡単にいうと、...T
が書ける
例えば
type Strings = [string, string];
type Numbers = number[]
// [string, string, ...Array<number | boolean>]
type Unbounded = [...Strings, ...Numbers, boolean];
こんな使い方もある
もっとスムーズに型が定義できる
type Foo<T extends unknown[]> = [string, ...T, number];
type T1 = Foo<[boolean]>; // [string, boolean, number]
type T2 = Foo<[number, number]>; // [string, number, number, number]
type T3 = Foo<[]>; // [string, number]
だから何? どこが便利?
declare function hello(name: string, msg: string): void;
// 上記と同じです
declare function hello(...args: [string, string]): void;
// もっと活用しましょう
declare function h(a: string, b: string, c: string): void
// 同じです!
declare function h(a: string, b: string, ...r: [string]): void
// 同じです!!
declare function h(a: string, ...r: [string, string]): void
// 同じです!!!
declare function h(...r: [string, string, string]): void
型定義を汎用化に
HasCallback
type HasCallback<T extends unknown[]> =
(...t: [...T, (...args: any[]) => any]) => void;
declare const foo: HasCallback<[string]>
foo('hello', function() {}) // 👍
foo('hello') // 💥 breaks
declare const bar: HasCallback<[string, number]>
bar('hello', 2, function() {}) // 👍
bar('hello', function() {}) // 💥 breaks
bar('hello', 2) // 💥 breaks
もっと詳しく
こちらはおすすめです。
TypeScript 4.0で導入されるVariadic Tuple Typesをさっそく使いこなす
Labeled Tuple Elements
従来の配列定義は、タイプのみとなりますが、現在ラベル付けることができます。
// before
type Range = [number, number];
// after
type Range = [start: number, end: number];
// other sample
type Foo = [first: number, second?: string, ...rest: any[]];
type Bar = [first: string, number];
// ~~~~~~
// Error! ラベルは、一部のみ付けることはエラーとなります
Dynamic Function Parameter Definition
Class Property Inference from Constructors
Class の constructor
関数のパラメータから、Class 属性のタイプを自動的に判断できるのものです。
タイプ自動判断
class Square {
// 旧: any, 新: number
sideLength;
constructor(sideLength: number) {
if (Math.random()) {
this.sideLength = sideLength;
}
}
get area() {
return this.sideLength ** 2;
// ~~~~~~~~~~~~~~~
// error! Object is possibly 'undefined'.
}
}
本来は undefined
のところで、definite assignment assertion (!)
、ビックリマークを付けることで、初期化済みと見なし
class Square {
// definite assignment assertion
// v
sideLength!: number;
// ^^^^^^^^
// type annotation
constructor(sideLength: number) {
this.initialize(sideLength)
}
initialize(sideLength: number) {
this.sideLength = sideLength;
}
get area() {
return this.sideLength ** 2;
}
}
Short-Circuiting Assignment Operators
新しい演算子が追加されました。 &&=
、 ||=
、??=
簡単例
// "Or Or Equals"
a ||= b;
a || (a = b);
// "And And Equals"
a &&= b;
a && (a = b);
// "QQ Equals"
a ??= b;
a ?? (a = b);
遅延初期化
let values: string[];
// Before
(values ?? (values = [])).push("hello");
// After
(values ??= []).push("hello");
遅延初期化
obj.prop ||= foo();
// 下記いずれと同じ
obj.prop || (obj.prop = foo());
if (!obj.prop) {
obj.prop = foo();
}
unknown on catch Clause Bindings
現状 catch
は any
を設定していますが、何でもできじゃうから、ちょっと危険ですね
try {
// ...
}
catch (e: unknown) {
// error!
// 'unknown' type には、'toUpperCase' の属性が存在しない
console.log(e.toUpperCase());
if (typeof e === "string") {
// works!
// type 限定すれば、使えます。変換は必要ない
console.log(e.toUpperCase());
}
}
Editor Improvements
Convert to Optional Chaining
/** @deprecated */ Support
/** @deprecated *
をドキュメントに付けると、取り消し線が表示されます。
参考資料