Description
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 let
outside 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