You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Filter with a type guard fails to narrow when the type guard's predicate is a tuple supertypeΒ #59054
import{expectType}from"ts-expect";declarefunctionTuple0IsNumberOrString(tuple: [unknown]): tuple is [number|string]declareconstt: [number|null]// t[0] is string | numberif(Tuple0IsNumberOrString(t)){t[0]// predictably the type guard narrows t[0] to number}// but filter fails to narrowconstlist=[t]constfiltered=list.filter(Tuple0IsNumberOrString)constf=filtered[0]![0]// number | null// strangely if the typeguard is changed, narrowing now worksdeclarefunctionTuple0IsNumber(tuple: [unknown]): tuple is [number]constfiltered2=list.filter(Tuple0IsNumber)constf2=filtered2[0]![0]// number
More examples on the playground
π Actual behavior
[number | null] & [number | string] generally gives a result of [number], but when a type guard is used with filter (specifically), the result is not the expected type of [number][], but rather the input type of [number | null][].
The problem occurs when the type guard's type assertion is a supertype of the expected item result type [number], but goes away if the type assertion is the same type or a subtype, i.e. [number] or [5]. The problem does not occur without the tuple wrapper.
changed the title [-]Filter with a type guard fails to narrow when the type guard's assertion is a tuple supertype[/-][+]Filter with a type guard fails to narrow when the type guard's predicate is a tuple supertype[/+]on Jun 27, 2024
Activity
[-]Filter with a type guard fails to narrow when the type guard's assertion is a tuple supertype[/-][+]Filter with a type guard fails to narrow when the type guard's predicate is a tuple supertype[/+]Andarist commentedon Jun 27, 2024
This depends on the
filter's definition that:With your type predicate you end up with:
This
Sdoesn't satisfy thisTso this overload can't be picked.RobertSandiford commentedon Jun 27, 2024
The second overload here allows the typeguard the work.
TS Playground Demo
The problem though is that T and may not be assignable to V, leading to unsafety. V needs a constraint that it is a supertype of T. e.g.
TS Playground with supertype constraint
Seems like we need supertype constraints to make progress on this #14520
RyanCavanaugh commentedon Jul 9, 2024
You would need to write this as
typescript-bot commentedon Jul 12, 2024
This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.