Add named type arguments
See original GitHub issueSearch 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.
interface Foo<T = SomeDefaultType, U> { ... }
// Current syntax
const foo: Foo<SomeDefaultType, string> ...
// Proposed syntax
const foo: Foo<U = string> ...
// yields foo: Foo<SomeDefaultValue, string>
This is loosely inspired on python’s named arguments:
def foo(bar = "I'm bar", baz):
...
foo(baz="I'm baz")
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:
interface Handler<Type = string, TPayload = object, TOutput = void> {
type: Type
handle(payload: TPayload): TOutput
}
Let’s say we have a class which implements the Handler interface but the defaults for Type
and TPayload
are fine for us and we only want to specify a type for TOuput
, currently it is mandatory that we pass type arguments for Type
and TPayload
:
class Foo implements Handler<string, object, Promise<number>>
If it was possible to pass type arguments by name we could use the considerably terser form:
class Foo implements Handler<TOutput=Promise<number>>
Examples
Fastify exposes types generic over many parameters with default values, such as
interface FastifyRequest<
HttpRequest = http.IncomingMessage,
Query = DefaultQuery,
Params = DefaultParams,
Headers = DefaultHeaders,
Body = DefaultBody
> { ...
With the proposed syntax we could create specialized interfaces with much less overhead such as
import * as fastify from 'fastify';
const app = fastify();
app.get('/users/:id', async (req: FastifyRequest<Params = {id: string }>, res: FastifyReply) => {
// req.params is strongly typed now
})
Checklist
My suggestion meets these guidelines:
- This wouldn’t be a breaking change in existing TypeScript/JavaScript code
- This wouldn’t change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript’s Design Goals.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:9
- Comments:8 (2 by maintainers)
@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? (contrived example)
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:
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:
Much better! No comments necessary.
Next, let’s consider the case of a Map:
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:
Or, using the equals-syntax that pedrolcn proposes in the OP:
Either way, the idea is that the aliases should show up whenever someone mouses over the map in VSCode, making the code self-documenting.