Skip to content

Spread Operator Doesn't Keep Object Type #46128

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

Open
GeoMarkou opened this issue Sep 29, 2021 · 4 comments
Open

Spread Operator Doesn't Keep Object Type #46128

GeoMarkou opened this issue Sep 29, 2021 · 4 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@GeoMarkou
Copy link

GeoMarkou commented Sep 29, 2021

Bug Report

πŸ”Ž Search Terms

spread operator interface object assign type

πŸ•— Version & Regression Information

Always

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about Spread Operator

⏯ Playground Link

Playground link with relevant code

image

πŸ’» Code

interface Person {
    firstName: string;
    surname: string;
}

const father:Person = {
    firstName: 'John',
    surname: 'Smith'
};

// This is a "Person"
const daughter = Object.assign({}, father);

// This is not a "Person", it just happens to have all the same properties
const son = { ...father };

πŸ™ Actual behavior

Using the spread operator to clone an object doesn't retain the object type. This isn't a huge problem, but it makes the Intellisense harder to read, and annoys me. I also feel like it would use more memory / CPU validating another object type instead of just referencing the original.

πŸ™‚ Expected behavior

Using the spread operator to clone the object should keep the same type.

@IllusionMH
Copy link
Contributor

IllusionMH commented Sep 29, 2021

Current behavior is more in line with what actually happens because const a = { ...b } in not always same type.
However would be nice to see proposed optimization when possible.

class WithPrivate {
    #hidden: string = 'hidden';
    visible: number = 1;
}

const withPrivate = new WithPrivate();

const noPrivate = { ...withPrivate };
const noPrivateError: WithPrivate = { ...withPrivate };

type SetterOnly= {
    set prop(val: string);
    regular: number;
}

declare const setterOnly: SetterOnly;

const noSetter = { ...setterOnly };
const noSetterError: SetterOnly = { ...setterOnly };

Playground

@GeoMarkou
Copy link
Author

I see - thank you for your explanation.

In the examples given, doesn't that mean Object.assign is actually wrong? MDN says

The Object.assign() method copies all enumerable own properties from one or more source objects to a target object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

In your example the #hidden field is not enumerable, but Typescript lets you use Object.assign anyway. If the set prop represents a setter via Object.defineProperty it also has the same issue of not being copied (but it is "triggered" whatever that means).

https://www.typescriptlang.org/play?ts=4.5.0-dev.20210929#code/MYGwhgzhAEDqCWAXAFgBQE7wG5kQU2gG8AoaM6AYmXgBMa8A7ALmgkUwYHNoBeaAcmp1G-ANylyWeBHgAjEHhYMArgFtZedL2gBGcQF9ixYAHsGbaAHckaTDnzaGeS3BsZsuPAAoAlONPmiNAMJu72eACi6Ogm6EwIKGGe2oTQAHQZ1ol2yfr+ZhYhSfgAglDwnMwJth4OfADysgBWeMCIaZAylV6E+gA0Vm45+H5GiACeAA4EAMp4iPjo9Qwg4ykSZBDz0JMxk144ICxsHJyj5NDoeJzK4HHBahroBkYBFlsLmsurTHOfSys1nwSBcrjc7iwAAx9DY7PYsfj8Yh5V4FIIhP6LKIxLTA9IZD6Lb5rFEY+ZY6KxNK7EyTbT8ADMYlRgWCJkxmjKXQY2kaLTaHXK3V6A0JX0BozJ-y5FQY1L29IATGIgA

class WithPrivate {
    #hidden: string = 'hidden';
    visible: number = 1;
}

const withPrivate = new WithPrivate();
const noPrivateError:WithPrivate = { ...withPrivate };
const noPrivateAssign:WithPrivate = Object.assign({}, withPrivate);

type SetterOnly = {
    set prop(val: string);
    regular: number;
}

const setterOnly:SetterOnly = {
    regular: 0,
    prop: ''
};

const noSetterError = { ...setterOnly };
noSetterError.prop = '3';

const noSetterAssign = Object.assign({}, setterOnly);
noSetterAssign.prop = '2';

@MartinJohns
Copy link
Contributor

@GeoMarkou The issue with Object.assign is missing #9726.

@andrewbranch andrewbranch added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Oct 4, 2021
@icecream17
Copy link

Linking to a similar comment: #36554 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants