-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Infer constrained generic parameters after instanceof check #17473
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
Comments
I started to file a new bug for this because I couldn't find the right search terms. I made a reproduction on Playground to show that this is still an issue -- note that 3 of the 4 assignments to I think Ryan was right, and it is in fact a Bug, not a Suggestion. This tripped me up today while refactoring, when I changed
to
This should be a drop-in replacement, but it's not. Consider
With the original definition of |
This is IMO a bug or design limitation. declare class myClass<ST = any>{
public read<T = ST>(): T;
}
let aClass = new myClass<string>();
if (aClass instanceof myClass) {
let result1 = aClass.read(); // any and not string
} else {
aClass; // never
} |
I ran into this today as well. The three.js typings have: export class Mesh<
TGeometry extends BufferGeometry = BufferGeometry,
TMaterial extends Material | Material[] = Material | Material[]
> extends Object3D {
...
material: TMaterial;
} My code is: if (obj instanceof THREE.Mesh) {
if (Array.isArray(obj.material)) {
// obj.material should be Material[], but it's any[]
}
} |
const prototypeProperty = getPropertyOfType(rightType, "prototype" as __String);
if (prototypeProperty) {
// Target type is type of the prototype property
const prototypePropertyType = getTypeOfSymbol(prototypeProperty);
if (!isTypeAny(prototypePropertyType)) {
targetType = prototypePropertyType;
}
} The implementation of
function getTypeOfPrototypeProperty(prototype: Symbol): Type {
// TypeScript 1.0 spec (April 2014): 8.4
// Every class automatically contains a static property member named 'prototype',
// the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. Given that this is appears to be part of the TypeScript v1.0 spec, it feels unlikely that this can be changed without causing other issues. That being said, it does look like a compiler change to match the requested behavior would be fairly easy to implement. (Would be more than happy to contribute such a change, if it makes sense) |
I think this is the same as #17253. However the other issue has a more accurate description of the problem. |
Note that the constraint is only appropriate if it's a covariant type parameter. If it's contravariant then |
My current proposed fix has the following logic:
The PR also assumes that this logic will be gated behind a new compiler option (which may not be the case). If this logic is disabled then it will infer |
Found temporary solution, which works fine for me - creating duplicated non-generic class with inheritance For the topmost issue comment it looks like this interface Foo {
foo: string;
}
class Bar<T extends Foo> {
constructor(readonly bar: T) {}
}
// creating a concrete class
class Temp extends Bar<Foo> {}
// taking type of that class to fix inference in generic class
// inside module - export BarProxy const instead of Bar class
const BarProxy = Bar as typeof Temp;
let a: unknown = new Bar({foo: 'foo'});
const barProxy: unknown = new BarProxy({foo: 'foo'});
console.log(a instanceof Bar);
console.log(a instanceof BarProxy);
console.log(barProxy instanceof Bar);
console.log(barProxy instanceof BarProxy);
if (a instanceof Bar) {
a.bar; // <-- a.bar should be 'Foo' instead of 'any'
}
if (a instanceof BarProxy) {
a.bar; // <-- works fine
} |
TypeScript Version: 2.4.0
When a variable passes an
instanceof
check generic type with constraints on the type parameter, apply to constraints to the variable. There is currently no clean way to handle the following without an explicit cast:Code
Expected behavior:
a.bar
is inferred as an instance ofFoo
.Actual behavior:
a.bar
isany
This change would only impact type checking, and will not affect compilation output.
The text was updated successfully, but these errors were encountered: