Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructing a object using destruction does not maintain type safety #41322

Closed
mad-it opened this issue Oct 29, 2020 · 3 comments
Closed

Constructing a object using destruction does not maintain type safety #41322

mad-it opened this issue Oct 29, 2020 · 3 comments

Comments

@mad-it
Copy link

mad-it commented Oct 29, 2020

TypeScript Version: 4.0.3

Code

interface Foo {
    bar : string
}

const foo: Foo = {
  bar: 'value',
  ...(true === true ? { baz: 1 } : { })  // No error :(
}

Expected behavior:

Expected behavior would be for an error to be highlighted underneath baz indicating that this property is not part of type Foo.

Actual behavior:

No error is shown thus breaking the contract that type Foo provides.

Playground Link: https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgGIHt3IN4ChkHIBCcUyAXMgM5hSgDmuAvrrguiDcjJpRlgF4c+YqUoByAG5wANgFcI4gDQiAdOoAUtBcgF7k2lAH4cyAEZwAXpQCMyJhVNMAlAQD0b5AB49QgO4AFgCeyMBUBgFhyLIy6H4QACYm5BrMQA

@MartinJohns
Copy link
Contributor

MartinJohns commented Oct 29, 2020

No error is shown thus breaking the contract that type Foo provides.

The contract is not broken. Everything that Foo says it will provide is present in your created object. Objects are allowed to have additional properties: What is structural typing?

If you spread a property that is incompatible with Foo you would get an error.

You are probably expecting the excess property checks to kick in (which is more of a linter-feature, not part of the type-system). In this case it's a duplicate of #39998.

@mad-it
Copy link
Author

mad-it commented Oct 29, 2020

You are right. Its a duplicate of #39998.

@mad-it mad-it closed this as completed Oct 29, 2020
@DetachHead
Copy link
Contributor

No error is shown thus breaking the contract that type Foo provides.

The contract is not broken. Everything that Foo says it will provide is present in your created object. Objects are allowed to have additional properties: What is structural typing?

If you spread a property that is incompatible with Foo you would get an error.

You are probably expecting the excess property checks to kick in (which is more of a linter-feature, not part of the type-system). In this case it's a duplicate of #39998.

from my understanding there seems to be two different rules for assignment:

  1. Assignment where the type of the value has to be assignable to the type of the variable and vice versa:
const foo: {foo: number} = {foo: 1, bar: 2} //error
  1. assignment where the type of the value is assignable to the type, but not the other way around:
const foo: () => {foo: number} = ()=>({foo: 1, bar:2}) // no error

it seems inconsistent which of these rules is used in many cases ie. my example from #41698. the compiler checks for excess properties when it's in the object directly (rule 1), but not when destructuring another object (rule 2):

foo = {...foo, baz: 1 } //Type '{ baz: number; bar: number; }' is not assignable to type 'Foo'. Object literal may only specify known properties, and 'baz' does not exist in type 'Foo'.
foo = {...foo, ...{baz: 1} } // no error 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants