📝

TypeScriptで型にもスプレッド構文使えるよ~って話

2022/01/28に公開
2

手っ取り早く、使い方を見たい方はこちらへジャンプ

スプレッド構文について

みなさん、JavaScriptのスプレッド構文を使っているだろうか?

まだ詳しくは知らないよという方は、まずこちらを見るとよい。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax

具体的なスプレッド構文の使い方

自分はオブジェクト型を扱うときは頻繁に使う構文である。具体的な例として、フロントエンドでの無限スクロールの実装が挙げられる。その際、既にあるデータと新しく取ってきたデータの結合にスプレッド構文を使う。

const prevData = [ /* 元からあるデータ */
  {
    id: 'article-id-1',
    title: '記事のタイトル',
    content: '....'
  },
  ....
];

const newData = [ /* 新しいデータ */
  {
    id: 'article-id-1',
    title: '記事のタイトル',
    content: '....'
  },
  ....
]

const data = [...prevData, ...newData]; /* 合体! */

イメージとしては...を付けることによって、配列の[]を外して取り扱う感じ。スプレッドつまり展開しているのだ。新しいデータ分、For文を回してArray.push()を行うより断然良い。

型においてのスプレッド構文とは

展開という意味は同じである。つまり型を展開すると言ってもいいかも(?) ユースケースとしては、配列が挙げられる。1つ目と2つ目以降が異なる配列の型はどのように書けばよいのだろうか。1つの案として、ユニオンタイプを用いた

type SpecificArray = (string|number)[];

もあるだろう。これでも今回実現したい型に近いづいた。これであれば1つ目や2つ目以降関係せず、stringまたはnumber型を格納できる。しかし、その値を使う際、タイプガードによって型を確定させる必要がある。また型が複雑になればなるほど、タイプガードも複雑となる。

くわえて、1つ目の型が確定しているのにも関わらず、オプショナルタイプを使うことに疑問を持ってしまう。

type StupidType = [string, number, number];

これは論外である。型によって、要素の数を決めてしまい汎用性がまったくない。

そこでのスプレッド構文である。

具体的な型においてのスプレッド構文の使い方

type ArrayType = [string, ...Array<number>];

ArrayPartial[1]などのAdvanced Typeの1つである。Array<number>number[]を同等の型を表す。そのため、

type ArrayType = [string, ...number[]];

という書き方でも良い。このようにして、1つ目はstring型、2つ目以降はnumber型という配列の型を定義できた。

勘違いしやすそうな表現
type ObjectType = ObjectType1 & ObjectType2;

これによってObjectTypeではObjectType1ObjectType2の型が使える。それに従って、

type ArrayType = [string] & number[];

これで1つ目にはstring型、2つ目以降はnumber型とはならない。ここでのArrayTypeは1つの要素数でstring型と定義される。

TypeScriptは奥深いなと改めて思ったのであった。

脚注
  1. Partialはジェネリクスの引数にオブジェクト型を入れることによって、すべてのキーをオプショナルタイプにするというAdvanced Typeである。 ↩︎

Discussion

glassmonkeyglassmonkey

型にspread演算子が使えると知らず大変助かりました。
1点確認なのですが、string|numberという表現はOptionalというよりはUnionかなと思ったのですがどうでしょう?

Cookie_ggCookie_gg

確かにUnionが正しいですね。修正しておきます!
ご指摘ありがとうございます🙇