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

Avoid "cannot assign an abstract constructor ..." through union type #13907

Closed
hediet opened this issue Feb 6, 2017 · 2 comments
Closed

Avoid "cannot assign an abstract constructor ..." through union type #13907

hediet opened this issue Feb 6, 2017 · 2 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@hediet
Copy link
Member

hediet commented Feb 6, 2017

I have this code in TS 2.1:

abstract class Test { _brand: string; }

function test1<T>(arg: { new(): T }): T { return null!; }
function test2<T>(arg: { new(): T } | Function): T { return null!; }

const a = test1(Test);
const b = test2(Test);

As discussed in #5843, test1 is not supposed to typecheck. However, surprisingly, test2 does.
TypeScript infers T for a and Test for b.
I don't know whether this is intended - can I build upon that behavior?

@RyanCavanaugh
Copy link
Member

The type { new(): T } | Function is equivalent to Function because { new(): T } is assignable to Function (the same way the type Dog | Animal is equivalent to Animal). We call this "subtype reduction" and in general it's really bad to write down a type that undergoes immediate reduction (we probably should have made this an error when we made union types, but too late now).

Most of the time when people write Function the actual type they want is (...args: any[]) => any):

`function test2<T>(arg: { new(): T } | ((...args: any[]) => any) ): T { return null!; }

const b = test2(Test); // Error

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Feb 6, 2017
@hediet
Copy link
Member Author

hediet commented Feb 6, 2017

Thanks for your answer!
But still, the type of the expression test2(Test) infers to Test. If { new():T } | Function is actually equivalent to Function, TypeScript should have inferred any, as it does for test3(Test) in

function test3<T>(arg: Function): T { return null!; }

However, I like TypeScripts current inference behavior as it solves #5843. I need this for my remoting library that instantiates abstract classes (which need to be classes so they can be decorated with metadata).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants