Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript allowing incorrect properties via object destructuring

Tags:

typescript

I'm running into an issue with TypeScript whereby an object using one type can be injected via a destructing assignment into an another object that uses a completely different type, and TypeScript doesn't show any errors for it.

An example being:

interface Pizza {
    cookingTime: number;
    size: "Small" | "Medium" | "Large";
}

interface Car {
    modelName: string;
    yearManufactured: number;
}

const produceMalformedPizza = (car: Car): Pizza => {
    return {
        ...car, // This is not a "Pizza" object but no errors are raised
        cookingTime: 10,
        size: "Small",
    }
}

console.log(
    produceMalformedPizza({
        modelName: "NotAPizza",
        yearManufactured: 1980
    })
)

/* Output:
[LOG]: {
  "modelName": "NotAPizza",
  "yearManufactured": 1980,
  "cookingTime": 10,
  "size": "Small"
} 
*/

I've tried to turn every possible strict flag on — and you can see it compiling online here.

If I try to return any specific properties in the produceMalformedPizza function, then the compiler raises errors, as expected — but it seems as though I can inject arbitrary object data using a destructuring (spread) assignment.

I'm relatively new to TypeScript, so perhaps this is expected behaviour? I.e. I can't use object spread destructuring with inferred type safety?

Edit:

As per the answer from @T.J.Crowder this is intentional.

  • There is some GitHub discussion about this issue specifically here: https://github.com/microsoft/TypeScript/issues/43499,
  • And also a proposal to support "Exact" types here: https://github.com/microsoft/TypeScript/issues/12936
like image 210
Sarreph Avatar asked Oct 24 '25 03:10

Sarreph


1 Answers

It's expected behavior. The object you're returning is a subtype of Pizza — it has all the properties Pizza requires (plus some that it doesn't).

TypeScript does do "excess property checks" but only in limited situations. For instance, if you were to put a non-Pizza property explicitly in that object literal, TypeScript would flag that up not because it's actually wrong from a type perspective (it's fine to use a subtype) but because it's probably a programmer mistake.

I'm slightly surprised it doesn't do that with ...car (since car has required properties), but it doesn't do excess property checks in all situations.

like image 65
T.J. Crowder Avatar answered Oct 25 '25 19:10

T.J. Crowder