## 事象 以下のコードが[[型述語推論 (TypeScript)|型述語推論]]されない。 ```ts declare let numberOrUndefines: (number | undefined)[]; const numbers = numberOrUndefines.filter((x) => !!x); // ^? (number | undefined)[] ``` `x = undefined`の場合は`!!x`が`false`になるため、`number[]`に推論されてほしい。 ## 原因 [[アロー関数 (JavaScript)|アロー関数]] `(x) => !!x` は[[型述語 (TypeScript)|型述語]]の定義を満たさないから。[[型述語 (TypeScript)|型述語]]の定義は以下。 > 関数 `function(x)` が以下2つの条件を満たすとき、`function(x): x is T` と表現できる。 > > 1. もし関数が`true`を返却するなら、`x`は`T`型である > 2. もし関数が`false`を返却するなら、`x`は`T`型ではない これを検証する。 #### 条件1について > 1. もし関数が`true`を返却するなら、`x`は`number`型である `x`が`undefined`を返す場合、この関数の戻り値は`false`になる。以上より、`x`は`number | undefined`であるため、**関数が`true`を返却するなら、`x`は`number`型である**と言える。つまり、**条件1を満たす**。 #### 条件2について > 2. もし関数が`false`を返却するなら、`x`は`number`型ではない 対偶として『`x`が`number`型であるなら、関数は`true`を返却する』を考える。 `x`が`number`型であったとしても、`x = 0`のときは関数は`false`を返す。よって、対偶条件は成立しないため、元の**条件2も成立しない**。 ## 解決方法 `(x) => x !== undefined` や `(x) => x != null` のような[[アロー関数 (JavaScript)|アロー関数]]に変更する。 `x = 0`のときでも`0 !== undefined`や`0 != null`は成立するため2つの条件を満たし、[[アロー関数 (JavaScript)|アロー関数]]は[[型述語推論 (TypeScript)|型述語推論]]される。 ## 参考 - [Documentation - TypeScript 5.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html#inferred-type-predicates)