Skip to content

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

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

Closed
paulluap opened this issue Jun 21, 2019 · 3 comments
Closed
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@paulluap
Copy link

paulluap commented Jun 21, 2019

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:

@jcalz
Copy link
Contributor

jcalz commented Jun 21, 2019

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.

@ahejlsberg ahejlsberg added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jun 21, 2019
@fatcerberus
Copy link

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
Copy link
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
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants