2
const foo : {[key:string]:string} = {'hello': 'world', 'hi': 'there'};
const bar : number = 42
const foobar = {...foo, bar}
console.log(foobar)
// { hello: 'world', hi: 'there', bar: 42 }

The type of foobar resolves to {bar: number}. Why is this? I would expect the type of foobar to be {[key:string]: string|number} or {[key:string]: string} & {bar: number}


EDIT: I'm particularly confused on why in some cases the types are determined correctly:

const foo : {a: number} = {a: 1}
const bar : string = "bar"
const foobar = {...foo, bar}
console.log(foobar)
// foobar is type {bar: string, a: number}

Why does this case work, and the first case doesn't?

8
  • 1
    Here you can find explanation stackoverflow.com/questions/59129738/… AFAIK, spread operator is not type safe (can't find issue yet). This issue may be related to indexed type: github.com/microsoft/TypeScript/issues/40529 Commented Jan 19, 2021 at 11:51
  • Indexed types are unsafe ) Commented Jan 19, 2021 at 12:02
  • They are unsafe, check. Is there a particular reason for this? Why is the spread operator sometimes safe, like in example 2? Commented Jan 19, 2021 at 12:04
  • 1
    The main problem is that TypeScript cannot guarantee in general that a type only has a given set of properties. For example interface Foo {a: number; b: string} suggests something with type Foo has an a and b property. However {a: 1, b: "two", c: false} is assignable to Foo. The compiler will not allow you to access c but it cannot assume it's not there. When getting all keys of an object there is no type safety in the general case. That leads to some behaviours that seem odd looking at types alone but are better suited for the real world code. Commented Jan 19, 2021 at 12:13
  • 1
    Quick demonstration of how an object that is assignable to an interface can have unexpected set of keys in some circumstances: Playground Link Commented Jan 19, 2021 at 12:23

1 Answer 1

1

I think this is because construction with spread cannot handle 'property declaration priority' properly. (indexed type properties have lower priority declaration). I think it can be improved in future versions. Try this:

const foobar = { ...foo, bar } as (typeof foo & { bar: typeof bar});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.