-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Type argument inference issues for methods of Generic Class with constraints other than primary types #21734
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'm trying different solutions to solve my issue, and I came over that extending classes and override methods with generic constraints doesn't work well. let func: (<T extends Array<number>>(items: T) => T) = (items: Array<number>) => {
return new Array<number>();
} The error I get is
|
If I change my code in first post and remove the generics and adds an interface instead it works as intended interface IOperator<TEntity> {
evaluate(items: Array<TEntity>): Array<TEntity>
}
abstract class Operator<TEntity> implements IOperator<TEntity> {
constructor() {
}
public evaluate(items: any): any {
return null;
}
}
class SkipOperator<TEntity> extends Operator<TEntity> {
constructor(public count: number) {
super();
}
public evaluate(items: Array<TEntity>): Array<TEntity> {
return null;
}
} But, as I mentioned in second post, it seems like constraints and type declarations isn't inherited since this doesn't work: let skip: SkipOperator<ICar> = new Operations<ICar>().first(SkipOperator); The error returned is
works fine in Typescript < 2.7 |
This example is better to understand where the problem really is - it has something to do with "type argument inference" that isn't solved correctly for child methods of a generic class with constraints other than primary types. This work as it should and throws an error because of the generic constraint let first = <T extends Number>(items: Array<T>): T => {
return items.shift();
}
let a = first([1,2,3]);
let b = first(["a","b","c"]); // error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'Number[]' This also works as it should, it inherits class Item<TType> {
public first<T extends Array<TType>>(items: T) {
return items.shift();
}
}
let c = new Item<number>().first([1,2,3]);
let d = new Item<number>().first(["a", "b", "c"]); //error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'number[]' But, whenever I use more complex structures as constraint it never fails class Car {
}
let e = new Item<Car>().first([new Car(), new Car(), new Car()]);
let f = new Item<Car>().first([1,2,3]); // no error because signature of first is first<number[]> instead of first<Car[]> The issue here is that the signature for e line is |
@lostfields the issue is that you have an empty class (see the FAQ). Adding a property or method to the class shows an error as you would expect |
@RyanCavanaugh great, then my last example works. So the issue is something with type argument inference with constructor arguments then? because this fails too: interface ICar {
id: number
}
interface IOperator<TEntity> {
valueOf(): TEntity
}
class SkipOperator<TEntity> implements IOperator<TEntity> {
constructor(public count: number = 5) {
}
public valueOf(): TEntity {
return null;
}
}
class Collection<TEntity> {
public first<T extends IOperator<TEntity>>(operator: new () => T): T {
return null;
}
}
let count: number = new Collection<ICar>().first(SkipOperator).count Throws error If I change |
I was bored, so I looked into this. The behavior changed in #19345. As far as I understand, TypeScript is matching up these two construct signatures:
Parameter of
Before #19345, the
Then After #19345, the
Then an inference of |
#19345 was very much intentional. I'd say the recommended thing would be to write public first<T extends { new(): IOperator<TEntity> }>(operator: T): InstanceType<T> { which makes the sample work without error (though does go against other guidance we write...) |
Uh oh!
There was an error while loading. Please reload this page.
I have a strange one that I can't figure out. It works fine with Typescript before 2.7.* and it has to be some kind of related to the abstract method with generics. When I remove that abstract method, it works. It's also working if I replace the abstract generic with any, from
public abstract evaluate(items: Array<TEntity>): Array<TEntity>
topublic abstract evaluate(items: Array<any>): Array<any>
I have no idea what to name this issue, sorry for the title.
TypeScript Version: 2.7.1
Code
Expected behavior:
compile without any error
Actual behavior:
throws an error;
error TS2339: Property 'count' does not exist on type 'Operator<ICar>'.
even when the signature of methodfirst
indicates it should return SkipOperator instead of Operator.Related Issues:
The text was updated successfully, but these errors were encountered: