先日このPRがマージされていたので早速試してみた。
https://github.com/Microsoft/TypeScript/pull/24897
以下で NightlyBuild が試せる。
npm install typescript@next
spread expression
v2.8 から Type inference in conditional types で、推論中に n番目のキャプチャ をとることができていた。 v3.0 からは spread expression が可能になるため以下の様な Tuple n番目のキャプチャをとることが可能。
typing.ts
// v2.8 から可能になった Type inference in conditional types による
// n番目引数のキャプチャ
type A1<Func> = Func extends (a1: infer A, ...args: any[]) => any ? A : never
type A2<Func> = Func extends (a1: any, a2: infer A, ...args: any[]) => any ? A : never
// v3.0 NightlyBuild では以下の spread expression が可能
type I0<Tuple> = Tuple extends [infer A, ...any[]] ? A : never
type I1<Tuple> = Tuple extends [any, infer A, ...any[]] ? A : never
以下の通り可変長引数を Tuple として扱えることが書かれている。
Strong typing of bind, call, and apply
PR に書いてある通りで、この機能の追加 + ThisType で mixin などの推論が強力になると思われる。また、可変長引数によって処理を振り分けたりするAPIを持つライブラリに有効。雑に何かを書いてみた。(こんな節操のないコードが存在しないことを祈りたい…)
convert.js
function convert(...args) {
if (typeof args[0] === 'string') {
return [...args].map(arg => String(arg))
}
if (typeof args[1] === 'boolean') {
return [...args].map(arg => Boolean(arg))
}
if (typeof args[2] === 'number') {
return [...args].map(arg => Number(arg))
}
return args
}
convert.ts
type NSB = number | string | boolean
type I0<T> = T extends [infer A, ...any[]] ? A : never
type I1<T> = T extends [any, infer A, ...any[]] ? A : never
type I2<T> = T extends [any, any, infer A, ...any[]] ? A : never
type isFirstArgString<T> = I0<T> extends string ? T : never
type isSecondArgBool<T> = I1<T> extends boolean ? T : never
type isThirdArgNumber<T> = I2<T> extends number ? T : never
type ConvertedList<T> = T extends isFirstArgString<T> ? string[] :
T extends isSecondArgBool<T> ? boolean[] :
T extends isThirdArgNumber<T> ? number[] :
T
function convert<T extends NSB[]>(...args: T) {
if (typeof args[0] === 'string') {
return [...args].map((arg: NSB) => String(arg)) as ConvertedList<T>
}
if (typeof args[1] === 'boolean') {
return [...args].map((arg: NSB) => Boolean(arg)) as ConvertedList<T>
}
if (typeof args[2] === 'number') {
return [...args].map((arg: NSB) => Number(arg)) as ConvertedList<T>
}
return args as ConvertedList<T>
}
const T1 = convert('0', true, 2) // T1: string[] = ["0", "true", "2"]
const T2 = convert(0, true, 2) // T2: boolean[] = [false, true, true]]
const T3 = convert(0, '1', 2) // T3: number[] = [0, 1, 2]
const T4 = convert(0, '1', '2') // T4: [0, "1", "2"] = [0, "1", "2"]
スキーマが微妙に違うインスタンスを配列に保持している場合、抽出したインスタンスの規約を推論出来るなども考えられそう。強い。