TypeScript で明示的に型を指定する必要があって、それが関数の返り値になる場合
値に型を指定して関数の返り値の型を推論させるより、関数の返り値の方で指定したい
const fn1 = () => {
return [
{ foo: "bar" },
] as Foo[]
}
const fn2 = (): Foo[] => {
return [
{ foo: "bar" },
]
}
fn1
より fn2
のようにしたい
fn2
の型情報を取得するときに、 fn1
の書き方だと関数の内部まで見ないといけなくて重くなるはずだし
また、推論の方法だと、別の return も追加できて、その return が同じ型を返さなくてもエラーにならない
でも、その関数を使うところでエラーになる可能性はあって、そこでエラーになると原因が分かりづらいエラーになる
なのでどうせ書くなら関数の返り値を明示的に書く fn2
形式にしたい
ただ、 fn2
の場合で return する値を変数に入れたいとき、同じ型を複数回書くことになる
const fn3 = (): Foo[] => {
const items: Foo[] = [
{ foo: "bar" },
]
if (baz) {
items.push({ foo: "baz" })
}
return items
}
const fn4 = (): Foo[] => {
const items = [
{ foo: "bar" },
]
if (baz) {
items.push({ foo: "baz" })
}
return items
}
fn3
は Foo[]
を 2 回書いてる
できれば 2 回書くのは避けたい
変更時に面倒だし、型エラーにならないレベルの修正なら修正漏れのままになる可能性もあるし
また TypeScript だとジェネリクスとか Union Type とかの組み合わせでとても長い型になることも頻繁にある
それを繰り返し書きたくない
ジェネリクスを関数風に使えば短くできなくはないけど、そのためだけにそこまではしたくない
fn4
形式で明示しなくても動くこともあるけど、 items
中の foo
のプロパティが string
になるので、
Foo
の定義で foo
が "bar" | "baz"
みたいな型の場合はエラーになる
また、入力中に item
が Foo[]
という情報がないので入力補完もされない
ということで諦めて fn1
に近い形にすることが多い
items
に型を指定して、関数自体には返り値の型を指定せず推論させる
ふと「関数内で自身の返り値型取れないのかな」と思って、 ReturnType
を試してみたら問題なさそうだった
const fn5 = (): Foo[] => {
const items: ReturnType<typeof fn5> = [
{ foo: "bar" },
]
if (baz) {
items.push({ foo: "baz" })
}
return items
}
fn5
自体の型は fn5
への代入文の次以降で有効になりそうで、その途中である関数内で参照しようとするとエラーになりそうな気はしたけどならないみたい
さすがに Foo[]
を明示的に書かずに推論させる場合は無理だったけど、明示的に書いてる場合は大丈夫らしい
この方法ありかなと思ったけど、 ReturnType
の中で fn5
という名前を書かないといけないのがイヤなところ
自身の返り値の型を指す専用のキーワードとかあればいいのに