Skip to content

Filter with a type guard fails to narrow when the type guard's predicate is a tuple supertypeΒ #59054

Closed as not planned
@RobertSandiford

Description

@RobertSandiford

πŸ”Ž Search Terms

filter type guard failing to narrow tuple supertype

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

Playground Link

πŸ’» Code

import { expectType } from "ts-expect";

declare function Tuple0IsNumberOrString(tuple: [unknown]): tuple is [number | string]
declare const t: [number | null] // t[0] is string | number
if (Tuple0IsNumberOrString(t)) {
    t[0] // predictably the type guard narrows t[0] to number
}

// but filter fails to narrow
const list = [t]
const filtered = list.filter(Tuple0IsNumberOrString)
const f = filtered[0]![0] // number | null

// strangely if the typeguard is changed, narrowing now works
declare function Tuple0IsNumber(tuple: [unknown]): tuple is [number]
const filtered2 = list.filter(Tuple0IsNumber)
const f2 = 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.

πŸ™‚ Expected behavior

The filter result should be [number][]

Additional information about the issue

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Not a DefectThis behavior is one of several equally-correct options

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions