TypeScript の可変長タプル型における共用体の分配 ― 2022年06月09日 01時29分
TypeScript の可変長タプル型 (variadic tuple types) とは、配列型やタプル型を展開して別のタプル型の一部として使える機能のことです (「TypeScript 4.0で導入されるVariadic Tuple Typesをさっそく使いこなす - Qiita」に詳しいです)。記法としては、展開する型の直前に三連続のドット ...
を記述します。例えば、
type Sandwich<Fillings extends unknown[]> = ['bread', ...Fillings, 'bread'];
のように具材 (filling) をパン (bread) で挟む Sandwich
型があったとき、Sandwich<['ham']>
型は ['bread', 'ham', 'bread']
型に展開されます。
type HamSandwich = Sandwich<['ham']>;
// → ['bread', 'ham', 'bread']
type BLTSandwich = Sandwich<['bacon', 'lettuce', 'tomato']>;
// → ['bread', 'bacon', 'lettuce', 'tomato', 'bread']
type RichHamSandwich = Sandwich<'ham'[]>;
// → ['bread', ...'ham'[], 'bread']
type TwoSlicesOfBread = Sandwich<[]>;
// → ['bread', 'bread']
ここで型引数 Fillings
に共用体型 (縦線 |
で区切った複数の型のうちのいずれかを表す型) を渡すとどうなるでしょうか。具材がハムか卵なら、できあがるのはハムサンドか卵サンドになります。つまり、Sandwich<['ham'] | ['egg']>
型は Sandwich<['ham']> | Sandwich<['egg']>
型と同等に扱われます。
type HamOrEggSandwich = Sandwich<['ham'] | ['egg']>;
// → ['bread', 'ham', 'bread'] | ['bread', 'egg', 'bread']
このように、T<A | B | C | (略)>
型が T<A> | T<B> | T<C> | (略)
型として扱われる挙動を「共用体の分配 (union distribution)」と呼びます。
共用体の分配は条件型 P extends Q ? R : S
でも発生しますが (「TypeScriptの型初級 - Qiita」に詳しいです)、可変長タプル型でも発生するのです。
条件型における共用体の分配では、never
型を分配しようとすると展開結果も never
型になります。これは可変長タプル型においても同じです。
type ImpossibleSandwich = Sandwich<never>
// → never
なお、可変長タプル型において any
型は any[]
型に展開されます。unknown
型を展開することはできません。
type AnySandwich = Sandwich<any>;
// → ['bread', ...any[], 'bread']
type UnknownSandwich = Sandwich<unknown>;
// → Error: Type 'unknown' does not satisfy the constraint 'unknown[]'.
可変長タプル型で共用体の分配が発生するというのは、可変長タプル型を導入した pull request の説明に書かれています。私はこの挙動を、type-challenges の回答のひとつをきっかけに知りました (その回答は誤答なのですが)。
- When the type argument for
T
is a union type, the union is spread over the tuple type. For example, [A, ...T, B]
instantiated with X | Y | Z
as the type argument for T
yields a union of instantiations of [A, ...T, B]
with X
, Y
and Z
as the type argument for T
respectively.
Variadic tuple types by ahejlsberg · Pull Request #39094 · microsoft/TypeScript
コメント
トラックバック
このエントリのトラックバックURL: http://nanto.asablo.jp/blog/2022/06/09/9498227/tb
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※投稿には管理者が設定した質問に答える必要があります。