3

I don't understand why Typescript doesn't highlight this as an error ...

When I conditionally add to an object a new property that doesn't exist in that object type definition, Typescript does assign it

  type Filters = {
      keywords: Array<string>
    }
    
    const condition = 1;
    
    let filters: Filters = {keywords: ['keyword']}
    
    filters = {
      ...filters,
        ...(condition && {...{ tags: ['tag']}}),
      }

Results:

filters: {
  keywords:["keyword"]
  tags:["tag"]
}

While I expected to get this error:

Object literal may only specify known properties, and 'tags' does not exist in type 'Filters'.

PS: I get the expected error when I try to add the same property this way:

filters = {...filters, tags: ['tag']}
4
  • Does this answer your question? Interesting behaviour: Object literal may only specify known properties Commented Sep 29, 2022 at 15:19
  • @caTS in the example of that thread, it's the same example as mine .. and the answer said >>Once it gets copied to the Person only the name property continues to exist<< but in fact, the object was copied to the Person and the property age does still exist and can be used at any time. 🤔 Commented Sep 29, 2022 at 15:39
  • I'd say this is a missing feature of TypeScript, as requested in microsoft/TypeScript#39998 Excess property warnings only happen in object literals and only in certain contexts, and nobody has implemented a check for spreading inline object literals. If that fully addresses your question I can write up an answer; otherwise, what am I missing? (Please mention @jcalz in your reply so I will be notified) Commented Sep 29, 2022 at 15:50
  • @jcalz Yup, since nobody has implemented a check for spreading inline object literals. that would fully answer my question ... Thank you! Commented Sep 29, 2022 at 15:59

1 Answer 1

1

This is currently a missing feature of TypeScript; excess property checks only happen in certain contexts, and so far nobody has implemented the sort of contextual checking of the contents of inline objects that are spread into outer objects.

There's an open feature request for this at microsoft/TypeScript#39998. It's currently marked as "Awaiting More Feedback" so you might want to go to that issue, give it a 👍, and describe in a comment your use case and why it is compelling. I doubt taking such an action would have much of an effect, but it wouldn't hurt.


As far as I know there isn't a great workaround to give you this behavior. If you want to use a helper function like

const noExcess = <T extends object>() =>
  <U extends { [K in keyof U]: K extends keyof T ? T[K] : never }>(u: U) => u;

And specialize it for Filters:

const noExcessFilters = noExcess<Filters>();

And then call it:

const z = noExcessFilters({
  ...filters,
  ...(condition && { tags: ['tag'] }),
}); // error!   Types of property 'tags' are incompatible.

it will flag situations like this, but I don't know if it's worth it to you.

Playground link to code

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.