Skip to content

Proposal: Support switch/if type guards with destructuring #13403

Closed
@ericanderson

Description

@ericanderson

For a lot of code duplication, its often helpful to destructure objects for later use. Type guards on switch/if help a lot in preventing unnecessary casts, but could be extended to infer a deeper understanding in some cases.

Lets use a trivial example:

interface Car {
    type: "Car",
    something: number
}

interface Truck {
    type: "Truck"
    something: boolean;
}

function takesNumber(v: number) {}
function takesBoolean(v: boolean){}

function doStuff(vehicle: Car | Truck) {
    switch (vehicle.type) {
        case "Car":
            takesNumber(vehicle.something); // okay
            break;

        case "Truck":
            takesBoolean(vehicle.something); // okay
            break;
    }
}

function doStuffDestructured(vehicle: Car | Truck) {
    const {type, something} = vehicle;

    switch (type) {
        case "Car":
            takesNumber(something); // error, not assignable
            break;

        case "Truck":
            takesBoolean(something); // error, not assignable
            break;
    }
}

In doStuffDestructured, we can logically infer that because we destructured vehicle at a moment in time, that the types/values are tied together, just as we in doStuff.

At a minimum I would propose this works for const destructuring as you can make reasonable assumptions outside of function scope:

let vehicle: Car | Truck = getVehicle();
const {type, something} = vehicle;
function doStuffDestructuredOutOfScope() {
    switch (type) {
        case "Car":
            takesNumber(something); // error, not assignable
            break;

        case "Truck":
            takesBoolean(something); // error, not assignable
            break;
    }
}

It seems to follow that for destructuring with letoutside of scope means we cannot track if the values have been assigned to something else, but could technically support let destructuring within scope. Honestly, I think its too hard to reasonable about for most end users that only supporting this for const is reasonable.

Thanks
CC/ @Andy-MS @ahejlsberg @mhegazy @RyanCavanaugh

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions