Skip to content

Spread operator does not call property getters #26547

Closed

Description

Search Terms:
spread operator, property getter

Code

interface IWhatever {
    readonly value: number;
}

class Whatever implements IWhatever {
    public get value() {
        return 42;
    }
}

const whatever: IWhatever = new Whatever();
const obj = { ...whatever, otherValue: 43 };
console.log(obj);

Expected behavior:
{ value: 42, otherValue: 43 }

This is expected because a readonly property of an interface can be implemented with a getter. The code using the interface cannot know that the property is implemented with a getter and therefore expects to see the property of the interface in the result.

Actual behavior:
{ otherValue: 43 }

Playground Link:
Link

Related Issues:

Activity

  1. RyanCavanaugh commented on Aug 20, 2018

    @RyanCavanaugh
    Member

    TypeScript doesn't change the behavior of JavaScript.

    image

  2. andreashuber69 commented on Aug 20, 2018

    @andreashuber69
    Author

    That's a fair point, ts isn't responsible for how js works. However, if we expand the example code just a little bit, e.g. as follows...

    interface IWhatever {
        readonly value: number;
    }
    
    class Whatever implements IWhatever {
        public get value() {
            return 42;
        }
    }
    
    class Utility {
        public static Do(x: IWhatever) {
            return x.value;
        }
    }
    
    const whatever: IWhatever = new Whatever();
    const obj = { ...whatever, otherValue: 43 };
    console.log(Utility.Do(obj));

    ... it becomes clear that the compiler does assume that obj implements the interface, otherwise the code should not compile. More precisely, the compiler falsely assumes that obj will always have a value property even though there's the possibility that it might not.

  3. RyanCavanaugh commented on Aug 20, 2018

    @RyanCavanaugh
    Member

    See also #26287

    I'm not sure what you're proposing happen. We don't track own/enumerability (see other open issues on that) so what line should be an error?

  4. andreashuber69 commented on Aug 20, 2018

    @andreashuber69
    Author

    I'm not sure what should happen, I just think this is a hole in the type system.

    If I had to implement this, I'd say the compiler should not make any assumptions what properties are added to an object by the spread operator. So, the call to Utility.Do should be flagged because obj cannot be guaranteed to implement the IWhatever interface. The programmer could still make the call by casting obj to IWhatever first.

  5. andreashuber69 commented on Aug 20, 2018

    @andreashuber69
    Author

    And yes, #26279 is very related. The issue only talks about classes with getters, so I'm not sure whether the fix would also correct the issue WRT interfaces as shown above.

  6. RyanCavanaugh commented on Aug 20, 2018

    @RyanCavanaugh
    Member

    It wouldn't fix this case due to the indirection via IWhatever

  7. andreashuber69 commented on Aug 21, 2018

    @andreashuber69
    Author

    Ok, thanks. How are we going forward with this problem (if it is one)? Should I file another issue that more succinctly explains the matter?

  8. RyanCavanaugh commented on Aug 21, 2018

    @RyanCavanaugh
    Member

    I don't think there's anything to do about it unless we were going to add a --strictOwnAndEnumerability flag to enforce tracking ownness/enumerability on all properties, which seems extraordinarily unlikely.

  9. CHBaker commented on Dec 14, 2018

    @CHBaker

    Would it be possible to type cast the spread operator value with the properties it is filling in? I think that would be useful instead of assuming the coder is correct

  10. ChemaCLi commented on Apr 6, 2022

    @ChemaCLi

    I made it in this way:

    function getModelProperties (model: any) {
      return Object.values(model)['0'] as any
    }
    
    const student = new Student()
    student.name = "Chema" // supose you have the name setter
    
    console.log({ data: { ... getModelProperties(student)} })
    // { data: { name: "Chema" } }
  11. Brain2000 commented on Jun 10, 2024

    @Brain2000

    It seems the spread operator in Javascript skips over getters in classes, but not in objects.
    Sometimes I feel the person implementing Javascript is really high.

    class C { get x() { return 1; }}
    const c = new C();
    console.log({...c});  <---does not show x
    
    const c = { get x() { return 1; }}
    console.log({...c}); <---does show x
    
  12. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions