-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Add named type arguments #38913
Comments
The arguments are the thing that go in at the use site; the parameters are the ones at the declaration site. |
Thanks for the clarification, I always mix these terms up. I updated the description to use them correctly |
@Airblader how a weaker proposal can supersede a stronger one? (optional sequential type arguments) vs (named type arguments). I don't buy that issues in #26346 are inherent to the idea itself. |
You can call it an alternate approach to the raised use-cases instead of a superseding approach, if you want, but that's what @weswigham called it when he closed the issue. Either way, this is a duplicate. The use-case raised in the issue here can just as well be solved with the superseding/alternate approach, so it's a valid replacement. In contrast, it doesn't raise issues such as type argument naming becoming public API. |
@Airblader The OP's goal of making the declaration terser would indeed be covered by pr #26349, but there's another use imo, which is clarity to the reader, in the same way that named arguments to functions confer. I'd rather say this: (1)
than this: (2)
In 2, does the reader know what string is for in B? Or number or Date? |
@paulnelson2 In addition to the example presented there, there is also the case where the user wants to utilize one of the arguments, but not all. For example in interface Request<
P = core.ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = core.Query,
Locals extends Record<string, any> = Record<string, any>
> extends core.Request<P, ResBody, ReqBody, ReqQuery, Locals> {} It is quite logical to want to overwrite just one of those params, such as the app.get("/", (req: Request<ReqBody = { foo: string, bar: boolean }>, res) => {
// it knows it's a string and must exist
const foo = req.body.foo;
}); |
In the OP, pedrolcn proposes that named type arguments would allow end-users to more-easily instantiate generic objects with lots of default parameters. However, I believe that named type arguments have an entirely different utility - for documentation. Consider the following. Before TypeScript 4.0, the following code was common: /** The first element is the index of the foo array, the second element is the index of the bar array. */
type MyTuple = [number, number]; This is not ideal, because we are forced to write comments to explain what the code does. TypeScript 4.0 fixes this problem by allowing us to write more expressive code with the named tuple feature: type MyTuple = [fooArrayIndex: number, barArrayIndex: number]; Much better! No comments necessary. Next, let's consider the case of a Map: /** The map keys are foo array indexes, the map values are bar array indexes. */
const myMap = new Map<number, number>(); The similarity to the previous example should be clear. It would be ideal to refactor away this JSDoc comment in the exact same way that we just did with the tuple. But how? There's no analogous "named tuple" feature for generic type parameters. What we really want to do is to write this, using the same colon-syntax as with named tuples: const myMap = new Map<fooArrayIndex: number, barArrayIndex: number>(); Or, using the equals-syntax that pedrolcn proposes in the OP: const myMap = new Map<fooArrayIndex = number, barArrayIndex = number>(); Either way, the idea is that the aliases should show up whenever someone mouses over the map in VSCode, making the code self-documenting. |
Search Terms
generics, type parameters, named parameter, named type parameter, type argument, named type argument
Suggestion
It should be possible to pass type arguments to a generic by name rather than positionally, eg.
This is loosely inspired on python's named arguments:
Use Cases
Generics only accept positional type arguments. If you have a generic accepting many type arguments, most or all of which having default values such as:
Let's say we have a class which implements the Handler interface but the defaults for
Type
andTPayload
are fine for us and we only want to specify a type forTOuput
, currently it is mandatory that we pass type arguments forType
andTPayload
:If it was possible to pass type arguments by name we could use the considerably terser form:
Examples
Fastify exposes types generic over many parameters with default values, such as
With the proposed syntax we could create specialized interfaces with much less overhead such as
Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: