Skip to content

Using undefined as a discriminator within a mapped type yields erroneous types when primitive intersections are involved #14471

Open
@weswigham

Description

@weswigham

TypeScript Version: 2.2.0

Code

// A *self-contained* demonstration of the problem follows...
type DeepReadonly<T> = {
    readonly [K in keyof T]: DeepReadonly<T[K]>;
}

interface FieldBrand {
    " do not use ": void;
}

type FieldId = number & FieldBrand;

interface DefOne {
    field: string | FieldId;
    kind: string;
}

interface DefTwo {
    field?: undefined; // Allow discriminant checks on 'field'
    value: string;
}

type Def = DefOne | DefTwo;

interface State {
    a?: Def;
    b?: Def;
}

type ROState = DeepReadonly<State>;

function lookupName(f: FieldId): string {
    return "";
}

function remapFieldsToNames(channels: ROState): ROState {
    const newState: State = {};
    for (const k of Object.keys(channels)) {
        const key = k as keyof ROState;
        const ch = channels[key];
        let replacement: ROState[typeof key] | undefined = undefined;
        if (ch) {
            if (ch.field) {
                const f = ch.field;
                if (typeof f === "number") {
                    f; // Should be FieldId or number, not never!
                    replacement = { ...ch, field: lookupName(f) };
                }
                else if (typeof f === "string") {
                    f; // correct
                }
            }
        }
        newState[k] = replacement || channels[k];
    }
    return newState;
}

Expected behavior:
There are no type errors in the above, and f after the typeof f === "number" check is either a number or FieldId.

Actual behavior:
replacement = { ...ch, field: lookupName(f) }; has a type error and f is of type never.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs InvestigationThis issue needs a team member to investigate its status.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions