Skip to content

missing properties after applying spread operator on instance of abstract type  #32022

Closed
@paulluap

Description

@paulluap

TypeScript Version: 3.5.2

Search Terms:
spread operator type error, Object.assign,
Code

abstract class Base { 
    abstract get a(): string;
    abstract get b(): string;
}
class A extends Base{ 
    a: string
    b: string
}
const a1 : Base = new A() 
const a2 : Base = {...a1}  //reports error: Type '{}' is missing the following properties from type 'Base': a, bts(2739)

const a3 : Base = a1
const a4 : Base = Object.assign({}, a1)

Expected behavior:
code compiles

Actual behavior:
reports error on a2
Type '{}' is missing the following properties from type 'Base': a, bts(2739)

Playground Link:
https://www.typescriptlang.org/play/#src=abstract%20class%20Base%20%7B%20%0D%0A%20%20%20%20abstract%20get%20a()%3A%20string%3B%0D%0A%20%20%20%20abstract%20get%20b()%3A%20string%3B%0D%0A%7D%0D%0Aclass%20A%20extends%20Base%7B%20%0D%0A%20%20%20%20a%3A%20string%0D%0A%20%20%20%20b%3A%20string%0D%0A%7D%0D%0Aconst%20a1%20%3A%20Base%20%3D%20new%20A()%20%0D%0Aconst%20a2%20%3A%20Base%20%3D%20%7B...a1%7D%0D%0Aconst%20a3%20%3A%20Base%20%3D%20a1%0D%0Aconst%20a4%20%3A%20Base%20%3D%20Object.assign(%7B%7D%2C%20a1)

Related Issues:

Activity

jcalz

jcalz commented on Jun 21, 2019

@jcalz
Contributor

In classes, getters go on the prototype like methods, and so object spread won't copy them:

class X {
  get x() {
    return "x";
  }
}
let y = { ...new X() }; // {}
console.log(y); // {}

Since a1 is only known to be Base, I think the a2 behavior is probably working as intended.

That the a4 behavior differs is likely a design limitation; the return type of Object.assign() is an intersection of its input types, which is incorrect for some edge cases.

This is related to #10727 and #28234 about how we don't have a real spread type and tend to use intersections in generic cases and Object.assign(), but that spread expressions with known concrete class instance only preserve non-method properties.

added
Design LimitationConstraints of the existing architecture prevent this from being fixed
on Jun 21, 2019
fatcerberus

fatcerberus commented on Jun 22, 2019

@fatcerberus

Yeah, I think this is the same deal as how in C++ if you only have a Base reference and call a method on it, you get the base class implementation unless the method is virtual (which requires a vtable, i.e. runtime dispatch). TS types have no runtime representation so if the compiler sees Base then it has no way to know it’s really dealing with a Derived.

paulluap

paulluap commented on Jun 24, 2019

@paulluap
Author

I see. Thanks for the replies.

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

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @jcalz@paulluap@fatcerberus@ahejlsberg

        Issue actions

          missing properties after applying spread operator on instance of abstract type · Issue #32022 · microsoft/TypeScript