Help us understand the problem. What is going on with this article?

TypeScriptでfilterを使って、アサーションなしでNullableな配列をNon-nullに型推論してもらう

Nullが許容される配列から、Nullを取り除いた値のみの配列を受け取りたい場合、ES5のfilterを使うことが通例でしょう。

TypeScriptには型推論があり、型を明示しなくてもよしなに型チェックをつけてくれますが、filterを使って型変換する場合は少し工夫が必要です。

実際にfilterの定義を見ながら、どうすれば型変換できるのかを見ていきましょう。

推論だけでは上手くいかない

例えば以下のようなnullableの配列に対して、型推論のみでfilterを使ってみましょう。

const values = [1, 2, null, 3, 4];
const filteredValues = values.filter(v => v !== null);

values(number | null)[]型となり、filteredValuesはnullを取り除いているのでnumber[]となるように見受けられますが、TypeScriptは内部実装までは見てくれず、相変わらず(number | null)[]型となってしまいます。

末尾にas number[]を付けることで型をnon-nullとみなす(=アサーション)こともできますが、実装から型が保証されているわけではないので、なるべく使わない方が望ましいです。

高階関数の返り値を指定して解決する

解決法を提示する前に、実際にfilterのTypeScriptの定義を見てみましょう。

filter<S extends T>(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];

filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[];

このようにfilterには2つの定義がありますが、上の方の定義にはSという型変数と、第一引数の関数の戻り値がSであることを示すvalue is Sが追加されています。

つまり第一引数の返り値がvalue is S型でなければ、any型の下の定義が自動的に使われ、filter対象の型がそのまま返ってきてしまうのです。

逆にいえば、第一引数の返り値がvalue is S型であれば、S型の配列、今回で言うnon-null値へ変換することができるようになります。

TypeScriptの「Type Guard」をおさらい

is ~という返り値ですが、これはTypeScriptのType Guardと呼ばれる機能で、アサーションを使わずに型を確定させることができます。

例えばNullableなstringが、stringであることを保証するには次のようにします。

const isString = (value: string | null): value is string => {
  return typeof value === 'string'
}

// もしくは…

const isString = (value: string | null): value is string => {
  return value !== null;
}

詳しくは「Type Guard」で調べて頂ければと思いますが、これを使うことで型を安全に狭めることができるようになります。

filterの第一引数にType Guardを使ってみる

それでは実際にfiterの第一引数にType Guardを使って、返り値の型変換をしてみましょう。

const values = [1, 2, null, 3, 4];
const filteredValues = values.filter((v): v is number => v !== null);

先ほどの例と違うのは、第一引数の返り値にv is numberを付与していることだけで実装は同じです。
しかしTypeScriptの型推論の結果はnumber[]型と、確かにNon-nullになっています。

ttiger55
以前はRoRやiOS開発→最近はGolangがメイン。個人的に今後やりたいのはTerraform、gRPCなど。学習したいのはオブジェクト指向のアーキテクチャ、コンピュータサイエンスなど。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした