Typescript: when merging a generic object type with new optional properties, these properties are not type checked

Created on 5 Feb 2020  路  6Comments  路  Source: microsoft/TypeScript

TypeScript Version: Nightly

Search Terms: generic spread optional property

Code

interface Test {
  readonly hi?: string[]
}

function test<T extends object>(value: T): Test {
  return { ...value, hi: true }
}

Expected behavior:
This should fail to type check.

Actual behavior:
It passes. Interestingly, changing any of the following causes it to fail:

  • Make the hi property non-optional
  • Replace T with object.

Related Issues: Not sure

Bug Fix Available

Most helpful comment

Optional properties were a mistake. /Half-kidding

As a rule of thumb, optional properties should only really be used in function/constructor parameter positions. And never as generic type constraints.

They shouldn't really be used in return types or other kinds of functions. Otherwise, you will find yourself in all kinds of soundness issues.

Not a TS team stance, just something I've personally observed.


Even when used to just type options objects for init, you can still run into soundness issues but they are far less likely to occur by accident

All 6 comments

While that's particularly egregious, the root cause is this:

interface Test {
    readonly hi?: string[]
}

function test<T extends object>(value: T): Test {
    return value; // `T` possibly doesn't satisfy `Test`
}

test({ hi: "potato" }); // ... clearly not a `Test`

T being assignable to Test seems.... dubious. Highly dubious.

Need 馃槻 reaction

T is assignable to {hi?: string[]} is apparently allowable because T is constrained to object, which is assignable to {hi?: string[]}.

const x: { hi?: string[] } = { hi: "no" } as object;

This, too, seems wrong.

And yet @ahejlsberg rates this as "Design Limitation", with "optional properties are very weakly checked; caveat empor"; so this is yours to triage now~

Optional properties were a mistake. /Half-kidding

As a rule of thumb, optional properties should only really be used in function/constructor parameter positions. And never as generic type constraints.

They shouldn't really be used in return types or other kinds of functions. Otherwise, you will find yourself in all kinds of soundness issues.

Not a TS team stance, just something I've personally observed.


Even when used to just type options objects for init, you can still run into soundness issues but they are far less likely to occur by accident

Moving fix back into 3.9.1 as I think it is very safe and has caught several legit issues.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

born2net picture born2net  路  150Comments

rwyborn picture rwyborn  路  210Comments

disshishkov picture disshishkov  路  224Comments

chanon picture chanon  路  138Comments

Gaelan picture Gaelan  路  231Comments