-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Suggestion: use receiver's declared type arguments as defaults to its class constructor #7782
Comments
I read somewhere you were using this concept of 'fresh' types in the compiler (I hope I'm not misusing it here but it did inspire me somewhat). What if the type of a new instance of a class type could be marked as 'fresh' as well? thus in: let x: Map<string, number> = new Map(); The resulting type of the expression However here: let y = new Map();
let x: Map<string, number> = y; Because the new instance was assigned to I mentioned this example as well: let createMap = () => new Map();
x: Map<string, number> = createMap(); Should the result of But What about this one? let createMap = <V, U>() => new Map<V, U>();
x: Map<string, number> = createMap(); I have no idea? Is this pattern really that common or important? |
"fresh" isn't really the right concept to use here, I think. The more common pattern used to improve inference in cases like this is contextual typing. We have a concept of inference sites for generic type parameters which are formed by correspondences between the types of the arguments and their corresponding type parameters. It should be sufficient to say that a generic contextual type e.g. That would also solve cases like this: interface MyMap<T> {
doesSomething: T;
}
declare function createMap<T>(cb: (a: T) => T): MyMap<T>;
class Foo {
x: MyMap<string>;
constructor() {
this.x = createMap(arg => arg.subtr(0)); // oops
}
} |
Thanks for the explanation! I was not even that sure what that 'fresh' concept really meant, so I guess I was just playing around with it a bit. I noticed that on discussions here you all use terminology like "type inference sites", "contextual types", "freshness", "narrowing", "widening" etc. maybe with time my understanding would sharpen but from a position of a user there are limits to how deeply I'd be able to go (I mean without spending an excessive amount of time on something which isn't really my "job"..). (BTW my intention with |
Accepting PRs on this. I tried to implement this with a somewhat naive approach and ran into problems with naked type parameters being inference candidates, which is bad. It'll take some effort to get this right. The test coverage we currently have seems sufficient to catch the weird cases, though. |
I run into this relatively simple pattern a lot:
Since
x
has already been defined with a particular set of type arguments, these arguments could be implicitly assumed as defaults to its type's constructor when invoked with it being the receiver (for simplicity I'm assuming here it is the exact constructor as declared e.g. not a derived class).I understand there will be cases where that would be very difficult or even impossible to achieve:
but these are relatively rare. Most of the time it's just:
Which instead could have been:
new Class<T>()
), or at least its default type arguments, in a way that's slightly unappealing from a "purist" point of view"? (though this doesn't seem like a "purist" language?). Perhaps some concept of "contextual baseline default type arguments" can be included as an integral part of the future proposal for default type arguments?The text was updated successfully, but these errors were encountered: