question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Javascript: Object.assign to assign property values for classes is not respected

See original GitHub issue

Perhaps TS should be able to identify Object.assign(this, ...) then infer the properties that are assigned to this? Or is this not possible to do? I am not sure.

TypeScript Version:
Version 3.0.3

Search Terms:

  • object assign
  • class
  • does not exist on type

Code A.js

export default class A {
  constructor ({ x, y, z }) {
    Object.assign(this, {x, y, z});
  }
  f () {
    return this.x;
  }
}

Expected behavior: TS should be able to identify x as a property of this.

Actual behavior: Throwing:

Property 'x' does not exist on type 'A'.

Playground Link: http://www.typescriptlang.org/play/#src=export default class A { constructor ({ x%2C y%2C z }) { Object.assign(this%2C {x%2C y%2C z})%3B } f () { return this.x%3B } }

Related Issues: no

Side Note: I am using TS with Javascript because YouCompleteMe switched to using TSServer for semantic completion. I absolutely love TS so was really happy about the switch! Thanks for the great work!

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:56
  • Comments:16 (1 by maintainers)

github_iconTop GitHub Comments

23reactions
eritbhcommented, Feb 20, 2019

Came here from #28883. I understand that in the general case, the type of the second argument to Object.assign could be of type any, but in my specific case I define that type via an interface beforehand:

interface MyConfig {
    someConfigProp: boolean;
}
class MyClass implements MyConfig {
    // Error: Property 'someConfigProp' has no initializer
    // and is not definitely assigned in the constructor.
    someConfigProp: boolean;
    constructor (config: MyConfig) {
        Object.assign(this, config);
    }
}

It seems to me that comparison between the types of this and config could be done, and if config is some type that’s not assignable to this, then that would be the condition where you couldn’t determine the type.

The alternative right now is to manually assign every property of the config interface to the corresponding class property, which works but is a pain:

interface MyConfig {
    someProp: boolean;
    someOtherProp: string;
    // ...etc
}
class MyClass implements MyConfig {
    someProp: boolean;
    someOtherProp: string;
    // ...etc
    constructor (config: MyConfig) {
        this.someProp = config.someProp;
        this.someOtherProp = config.someOtherProp;
        // ...repeated for every property of the config object
    }
}

(This whole thing gets even more ugly when dealing when using optional properties on the config object to allow the use of default values:

interface MyConfig {
    // these props are optional in the config object
    someProp?: boolean;
    someOtherProp?: string;
}
class MyClass implements MyConfig {
    // all props are required in the class, with default values
    someProp: boolean = false;
    someOtherProp: string = 'default value';
    constructor (config: MyConfig) {
        if (config.someProp !== undefined)
            this.someProp = config.someProp;
        if (config.someOtherProp !== undefined)
            this.someOtherProp = config.someOtherProp;
    }
}

and as you can see, with lots of properties on the config object, you quickly wind up with a large chunk of code that just does the same job Object.assign normally does, as it automatically handles optional properties. However, because Object.assign interprets a key with value undefined as present, this would be blocked on #13195 for full compatibility.)

Is there any way to achieve this right now? If not, is it viable to implement? I could look into putting a PR together, but no promises as I’ve never worked with TS’s source before.

17reactions
GongTcommented, Sep 3, 2018

Why not support return different thing from constructor()?

class X {
	public X: number;

	constructor() {
		return new Y;
	}
}

class Y extends X {
	public Y: number;
}

const obj = new X;
console.log(obj.Y); /// TS2339: Property 'Y' does not exist on type 'X'

It’s more common than only Object.assign.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Object.assign() - JavaScript - MDN Web Docs
The Object.assign() static method copies all enumerable own properties from one or more source objects to a target object.
Read more >
object.assign does not copy functions [duplicate]
As I mentioned in my answer, the properties that are not being copied (which you say contain functions), are probably on the prototype...
Read more >
14. New OOP features besides classes - Exploring JS
Only enumerable own properties: Object.assign() ignores inherited properties and properties that are not enumerable. Reading values: the values are read ...
Read more >
JavaScript Object.assign() - Programiz
The JavaScript Object.assign() method copies all enumerable own properties of given objects to a single object and returns it. In this article, you...
Read more >
JavaScript Object.assign() Method - GeeksforGeeks
Javascript · A TypeError is raised if the property is non-writable. · The target object can be changed only if the properties are...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found