question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add named type arguments

See original GitHub issue

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.

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:open
  • Created 3 years ago
  • Reactions:9
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
paulnelson2commented, Feb 16, 2022

@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)

interface A extends B<Indexer=string, Counter=number, Timestamper=Date> {}

than this:

(2)

interface A extends B<string, number, Date> {}

In 2, does the reader know what string is for in B? Or number or Date? (contrived example)

0reactions
Zamiellcommented, Jul 10, 2022

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Named and Optional Arguments - C# Programming Guide
Named arguments enable you to specify an argument for a parameter by matching the argument with its name rather than with its position...
Read more >
Named Type Arguments - Scala 3 - EPFL
Type arguments must be all named or un-named, mixtures of named and positional type arguments are not supported.
Read more >
Named Arguments in C++
This article will show you how to implement named arguments in C++, such as f(firstName = "John", lastName = "Doe)
Read more >
Code Syntax Style: Named/Positional Arguments - JetBrains
If you prefer to use named arguments for specific types of parameters, JetBrains Rider can help you enforce this practice.
Read more >
PHP 8: named arguments - Stitcher.io
You might have guessed it from the examples: named arguments allow you to pass input data into a function, based on their argument...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found