やりたいこと
Rubyでは、配列の頭に*をつけると配列が展開され、各要素を一つずつmethodの引数として渡すことができる。
def method1(arg1, arg2, arg3)
puts "一つ目の引数: #{arg1}"
puts "二つ目の引数: #{arg2}"
puts "三つ目の引数: #{arg3}"
end
args = ["hoge", 1, true]
method1(*args)
# => "一つ目の引数: hoge"
# "二つ目の引数: 1"
# "三つ目の引数: true"
TypeScriptでも同じことがしたい。
方法
spread演算子を使えば実現できる。
その際、展開する配列の型が要素数が引数の個数と同じで、引数の型を順番通りにもつ配列型となっている必要がある。
まずはありがちな失敗例を一つ挙げる。
失敗例
const method1 = (arg1: string, arg2: number, arg3: boolean) => {
console.log(`一つ目の引数: ${arg1}`)
console.log(`二つ目の引数: ${arg2}`)
console.log(`三つ目の引数: ${arg3}`)
}
type Args = string | number | boolean
const args:Args[] = ["hoge", 1, true]
method1(...args)
// => ...argsに対し警告がでる
この場合、
spread 引数には、組の種類を指定するか、rest パラメーターに渡す必要があります
という警告が出てコンパイルが通らない。
Args[]
は個数の情報を持たないし、どの位置にどの型があるのかもわからないためである。
繰り返すが引数の型が異なる場合は、
展開する配列の型が要素数が引数の個数と同じで、引数の型を順番通りにもつ配列型となっている必要がある。
そのように配列の型を指定するには下記二つの方法がある。
方法1: 配列の要素の型を明示する
const method1 = (arg1: string, arg2: number, arg3: boolean) => {
// 省略
}
const args:[string, number, boolean] = ["hoge", 1, true]
method1(...args)
// => 一つ目の引数: hoge
// 二つ目の引数: 1
// 三つ目の引数: true
重要なのはargs
に指定している[string, number, boolean]
の部分である。
このように要素の個数と特定の位置に含まれる型を明示している配列の型をタプル型という。
タプル型を使用することで、
- 引数の数と同じだけ要素が存在すること、
- 配列を展開した時に確実に引数の型と一致すること
が保証されるため、警告は解消される。
方法2: as constを使用する
配列の要素を明示する以外にもas const
を使用する方法がある。
配列に対して、as const
を使用して型アサーションを行うと、指定された配列はreadonlyなタプル型となる。
const method1 = (arg1: string, arg2: number, arg3: boolean) => {
// 省略
}
// argsの型は readonly ["hoge", 1, true]
const args = ["hoge", 1, true] as const
method1(...args)
// => 一つ目の引数: hoge
// 二つ目の引数: 1
// 三つ目の引数: true
この場合も方法1と同様、要素の数と特定の位置に含まれる要素の型が保証されるため、警告は解消される。
まとめ
- TypescriptでRubyのように複数の引数を配列でまとめて指定するためにはSpread演算子を使う
- Spread演算子で引数を渡す場合は配列の要素の型を明示するかas constを使用してタプル型を指定する
参考元
スプレッド演算子-TypesScript Deep Dive 日本語版