Skip to content
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

Spread operator in 'new' expressions support for ES5? #2369

Closed
saschanaz opened this issue Mar 16, 2015 · 8 comments
Closed

Spread operator in 'new' expressions support for ES5? #2369

saschanaz opened this issue Mar 16, 2015 · 8 comments
Labels
Help Wanted You can do this Suggestion An idea for TypeScript

Comments

@saschanaz
Copy link
Contributor

I've found that #1931 supports this only for ES6, but it seems ES5 also can do this in any way.

var arguments = [1, 2, 3, 4, 5];
new Array(...arguments);

This can be converted to ES5:

// Thanks to: http://stackoverflow.com/a/14378462/2460034
var arguments = [1, 2, 3, 4, 5];
new (Array.bind.apply(Array, [null].concat(arguments)));
// Result: [1, 2, 3, 4, 5]
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Mar 17, 2015
@RyanCavanaugh
Copy link
Member

Seems reasonable enough.

@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this and removed In Discussion Not yet reached consensus labels May 4, 2015
@RyanCavanaugh RyanCavanaugh added this to the Community milestone May 4, 2015
@RyanCavanaugh
Copy link
Member

Approved. Be sure to handle the case where the operand to new is a computed expression that needs to be cached in a temporary variable.

@tinganho
Copy link
Contributor

tinganho commented May 7, 2015

I'm almost done with a PR on this one. Though there are one issue with the type checker:

interface ObjectWithSpreadMethod {
    spreadMethod(x: number, y: number, ...z: string[]);
}

var spread: string[];
var objectWithSpreadMethod: ObjectWithSpreadMethod;

new objectWithSpreadMethod.spreadMethod(1, 2, "string");
new objectWithSpreadMethod.spreadMethod(1, 2, ...spread);
new objectWithSpreadMethod.spreadMethod(1, 2, ...spread, "string"); 

Isn't it correct TS code above? Why can't I do new objectWithSpreadMethod.spreadMethod on a method?

Shall I correct this behavior?

Playground:
http://www.typescriptlang.org/Playground#src=interface%20ObjectWithSpreadMethod%20%7B%0D%0A%20%20%20%20spreadMethod(x%3A%20number%2C%20y%3A%20number%2C%20...z%3A%20string%5B%5D)%3B%0D%0A%7D%0D%0A%0D%0Avar%20spread%3A%20string%5B%5D%3B%0D%0Avar%20objectWithSpreadMethod%3A%20ObjectWithSpreadMethod%3B%0D%0A%0D%0Anew%20objectWithSpreadMethod.spreadMethod(1%2C%202%2C%20%22string%22)%3B%0D%0Anew%20objectWithSpreadMethod.spreadMethod(1%2C%202%2C%20...spread)%3B%0D%0Anew%20objectWithSpreadMethod.spreadMethod(1%2C%202%2C%20...spread%2C%20%22string%22)%3B%20

@RyanCavanaugh
Copy link
Member

Seems like it should be typed like this:

interface ObjectWithSpreadMethod {
    spreadMethod: {
        new (x: number, y: number, ...z: string[])
    };
}

Alternatively:

interface ObjectWithSpreadMethod {
    spreadMethod(x: number, y: number, ...z: string[]): void;
}

The code as written has spreadMethod returning any, which is not a valid invocation target for new.

@tinganho
Copy link
Contributor

tinganho commented May 7, 2015

@RyanCavanaugh Ok thanks, I will land a PR later.

@mhegazy mhegazy modified the milestones: TypeScript 1.6, Community May 18, 2015
@mhegazy
Copy link
Contributor

mhegazy commented May 18, 2015

thanks @tinganho!

@mdcone
Copy link

mdcone commented Aug 20, 2015

Does this seem to just be a happy coincidence with Array? Using this technique with my own TS classes doesn't work.

Seems as if it really is impossible. According to MDN --

Apply for new

Example: In ES5 it is not possible to compose new with apply (in ES5 terms apply does a [[Call]] and
not a [[Construct]]). In ES6 the spread syntax naturally supports this.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

Further reading into the ES6 standard:

The Array constructor is the %Array% intrinsic object and the initial value of the Array property of the global object. When called as a constructor it creates and initializes a new exotic Array object. When Array is called as a function rather than as a constructor, it also creates and initializes a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.

Which tells me that using something that does a [[Call]] with an array (.apply() or .call()) also has the same effect as a [[Construct]].

I'm fine with allowing this behavior in this case, so maybe allowing for a warning to be emitted instead of an error, or for special casing the errors to give a hint to the programmer as to why a program isn't behaving as expected might be a useful thing.

@tinganho
Copy link
Contributor

@mdcone could you share your classes? I tested it with TS classes and it seems to work for me.

@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants