jolivier
jolivier

Reputation: 7645

Typescript type safety in conditional union type switch typing

I have a simple function taking a union type and a boolean as parameters and cannot manage to have it be typed by Typescript.

I have this code (playground here):

type A = 'a' | 'A';

function f(a: A, b: boolean): string {
    if (b) {
        switch (a) {
            case 'a': return '';
            case 'A': return '';
        }
    } else {
        switch (a) {
            case 'a': return '';
            case 'A': return '';
        }
    }
}

The compiler (when strictNullChecks is enabled) tells me Function lacks ending return statement and return type does not include 'undefined'.

I really don't want to add default cases since the goal here is to ensure that when I add new types in A I handle them correctly in f. And I don't see which branch I am missing.

I could fix it by writing (see the linked playground):

function g(a: A): string {
    switch (a) {
        case 'a': return '';
        case 'A': return '';
    }
}

function f2(a: A, b: boolean): string {
    if (b) {
        return g(a);
    } else {
        return g(a);
    }
}

(Of course in real life I need two different g functions but for the typing issue this is not important).

How can I let typescript compile f without introducing intermediate functions like g ?

Upvotes: 1

Views: 2423

Answers (1)

Murat Karagöz
Murat Karagöz

Reputation: 37604

You can add the default case to fix it e.g.

function f(a: A, b: boolean): string {
    if (b) {
        switch (a) {
            case 'a': return '';
            case 'A':
            default: return '';
        }
    } else {
        switch (a) {
            case 'a': return '';
            case 'A':
            default: return '';
        }
    }
}

You also fix it by using the never type by returning it e.g.

function f(a: A, b: boolean): string {
    if (b) {
        switch (a) {
            case 'a': return '';
            case 'A': return '';
            default:
                const _exhaustiveCheck: never = a;
                return _exhaustiveCheck;
        }
    } else {
        switch (a) {
            case 'a': return '';
            case 'A': return '';
            default:
                const _exhaustiveCheck: never = a;
                return _exhaustiveCheck;
        }
    }
}

Upvotes: 3

Related Questions