-
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: Generic Parameter Overloads #209
Comments
Couple of questions that come out of thinking about this:
class View<TModel extends Backbone.Model = Backbone.Model> {
...
}
// currently typed as View, with this feature would be now typed as View<Backbone.Model>
// because of the default type param value
var v: View;
var v: View; // infers View<Backbone.Model> because View had a constraint
var a: Array; // infers Array<any> because Array has no constraint on T In the past we didn't want to infer |
Yes, both alternatives can do it. I like the second one even better that the compiler figures the type parameter for you. I think that would cover most cases, but just in case, combination of these two also seems to be viable. |
One case I thought you don't want the compiler to automatically choose the default generic type for you is when you want to keep it to be generic, for example in class View<TModel extends Model> extends Events {
constructor(options?: ViewOptions<TModel>);
model: TModel;
collection: Collection<TModel>;
} So it's still good to enforce |
I dont want to be the "Me Too" guy but this is definitely needed for a signals library im using!
|
👍 |
👍 |
Glad this is still being considered. This feature can be taken as two things:
The first one can cover use cases for the second one, but the opposite is not true. If true C#-like Generic Parameter Overloads is supported where each overload defines its own implementation, then the compiler has to give a different name to each overload in the generated JS. For example, |
Any movement on this one? I've run into the situation where I want to do this:
But Instead I have to define them like this:
It's not the end of the world, but it is pretty annoying. |
@RonPenton We added generic defaults in #13487 for TS 2.3, so yes - we implemented the equivalent alternative to this. |
@weswigham I don't see how defaults are solving the problem with @RonPenton's example I tried this export interface Func<R=void> { (): R; }
export interface Func<R=void, P1=void> { (param1: P1): R; }
export interface Func<R=void, P1=void, P2=void> { (param1: P1, param2: P2): R; }
const fn1: Func = () => {};
const fn2: Func<string> = () => '';
const fn3: Func<string, number> = (param1: number) => ''; //error
const fn4: Func<string, number, boolean> = (param1: number, param2: boolean) => ''; //error but the compiler complains at and at
it seem like the compiler will always take the first overload of or am I doing something wrong here? |
You should only need to have one interface declaration, for one thing: export interface Func<R=void, P1=never, P2=never> { (param1: P1, param2: P2): R; }
const fn1: Func = () => {};
const fn2: Func<string> = () => '';
const fn3: Func<string, number> = (param1) => '';
const fn4: Func<string, number, boolean> = (param1, param2) => ''; The rest are just adding more call signatures, which will get resolved using overload resolution. If you add them; you need to make sure the "most specific" ones are added first, otherwise what you described can happen (they're all being matched against |
There are some drawbacks with that solution: export interface Func<R=void, P1=never, P2=never> { (param1: P1, param2: P2): R; }
const fn1: Func = () => {};
fn1(); // TS2554:Expected 2 arguments, but got 0. If I make all parameters optional, then there is no type safety in calling the methods with all expected parameters .... export interface Func<R=void, P1=never, P2=never> { (param1?: P1, param2?: P2): R; }
const fn1: Func = () => {};
const fn2: Func<string> = () => '';
const fn3: Func<string, number> = (param1) => '';
const fn4: Func<string, number, boolean> = (param1, param2) => '';
fn1(); // fine
fn2(); // fine
fn3(); // should raise error but does not
fn4(); // should raise error but does not |
@weswigham I don't believe that solves the issue. I tried to use default generic parameters like @lukas-zech-software did and ran into the same problems. The compiler expects parameters that don't exist. Try out your code, you'll see that it doesn't work:
|
I don't think default values work for the case I am interested in, either. I'm trying to get generic parameter binding working. Creators of a bindable would define the parameters that it accepts, and consumers would bind values for parameters through a "bind" call. Once all parameters are bound then the bind method is no longer available and the call method becomes available. This looks something like this
In some ways this is very much like the classic C++ factorial template metaprogramming example |
The suggestion is to allow generic parameter overloads like the following:
This is important because this would allow people to introduce generics in their library declarations without breaking large amounts of existing code for the consumers. We do this a lot in C#, and it is compatible with TypeScript design because it won't make any changes in the resulting javascript, and works pretty much like method overloads in TypeScript.
Related discussion: https://typescript.codeplex.com/discussions/452741
The text was updated successfully, but these errors were encountered: