Home > Software design >  Discriminated union not working when narrowing after array access
Discriminated union not working when narrowing after array access

Time:02-03

Given these two types:

type Prospect = {
    name: string;
}

type Client = {
    name: string;
    account: string;
}

Let's create a union where kind acts as the discriminator:

type Union = 
| {kind: "prospect", persons: Prospect[]} 
| {kind: "client", persons: Client[]};

const {persons, kind} = {} as Union

Type narrowing works as expected when accessing persons.

if (kind === "client") {
    persons.map(person => { // person: Client
        person.account // All good
    })
}

It, however, fails to work after accessing an individual element from persons.

const person = persons[0]
if (kind === "client") { // person: Prospect | Client
    person.account // Error
}

How can I achieve type narrowing after I have already accessed an array? I could add a kind field to Prospect and Client but that seems redundant given that persons is always an array of Prospect or Client and not a mix of both.

CodePudding user response:

You can move person access inside type guard:

if (kind === "client") { // person: Prospect | Client
    const person = persons[0]
    person.account // Ok
}

In your case of

const person = persons[0]
if (kind === "client") { // person: Prospect | Client
    person.account // Error
}

Typescript cannot guess that person/persons[0] didn't mutate and change type between assignment and type guard, so it cannot safely narrow type.

  • Related