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

generics Instantiated as null : {} causes other type errors to disappear #3733

Closed
bergmark opened this issue Jul 3, 2015 · 5 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@bergmark
Copy link

bergmark commented Jul 3, 2015

Examples:

class C<R>
{
  value : R;
  constructor(v? : R) { this.value = v }
}

// OK, no type error
var a : C<string> = new C("x");

// OK, type error
var b : C<string> = new C(1);
var c : C<string> = true ? new C("x") : new C(1);
var d : C<string> = new C(1) || new C<string>(null);
function e() : C<string> { if (false) { return new C(null) } else { return new C(1) } }

// Bad, no type error
var f : C<string> = true ? new C(null) : new C(1);
var g : C<string> = true ? new C(1) : new C(null);
var h : C<string> = (() => { if (false) { return new C(null) } else { return new C(1) } })();
var i : C<string> = new C(1) || new C(null);

Here, any time new C(1) is used it should have the type C<number> and not unify with C<string>. It seems like R not being known in new C(null) prevents these other type errors from occurring.

@DanielRosenwasser
Copy link
Member

I believe what is happening here is that you're getting C<any> from new C(null) and C<number> from new C(1). Between the two, C<any> "wins out" and is assignable to C<string>.

Surprisingly, --noImplicitAny doesn't report a problem with this. Wondering if @JsonFreeman or @danquirk know whether this is intentional or not.

@bergmark
Copy link
Author

bergmark commented Jul 3, 2015

Thanks for the clarification. It seems then that in e.g. x = p ? a : b there are only checks that a and b unify and that a+b unify with x. I think it would make sense to check that a and b unify with x individually. I was surprised that the typing differs between if statements and ternary expressions.

@hesselink
Copy link

@DanielRosenwasser What surprises me is that the behavior of new C(null) is different from e.g. [null] or { x : null }. Those are inferred to Array<any> and { x : any }, but ternary expressions like above fail to type check for them. What makes a user defined class different?

@DanielRosenwasser
Copy link
Member

Hey guys, I just remembered - this seems to be a duplicate of #531, but a symptom of #1436. What we proposed doing is widening type arguments to any at specific points instead of when inferring them.

@JsonFreeman
Copy link
Contributor

I think this is a duplicate of #1436, as @DanielRosenwasser said. I am still in favor of not widening when we infer a type argument. As @ahejlsberg points out, the cost is that we have to have a general algorithm for walking a type and performing widening, and the algorithm has to be resilient to circularities in the type. I don't think this is unreasonable. We do this for all the other type walks.

@JsonFreeman JsonFreeman added the Duplicate An existing issue was already created label Jul 6, 2015
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants