Skip to content

Supply label names in tuple types using type-level strings #56093

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

Open
5 tasks done
Diggsey opened this issue Oct 12, 2023 · 6 comments
Open
5 tasks done

Supply label names in tuple types using type-level strings #56093

Diggsey opened this issue Oct 12, 2023 · 6 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@Diggsey
Copy link

Diggsey commented Oct 12, 2023

πŸ” Search Terms

Labelled tuples

βœ… Viability Checklist

  • 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, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

⭐ Suggestion

It's already possible to manually specify labels when defining a tuple type:

type MyTuple = [foo: number, bar: string];

I propose that there be some syntax to allow these labels to be supplied explicitly in mapped types, eg.

type Labels = ["foo", "bar"]
type Values = [number, string]
type MyTuple = {
    // Hypothetical syntax
    [I in keyof Values]: Values[I] as Labels[I]
}

To be clear: there is still no way to "access" labels of tuples under this proposal. It's purely a way to add extra documentation into existing type definitions.

If the provided name can be determined to be a literal string type, then the value of that literal string is used as the tuple element name. In all other cases, the element is unnamed as before.

πŸ“ƒ Motivating Example

There are many cases where the developer can supply useful names, such as if the tuple is somehow derived from an object type, or similar.

My particular case involves taking a user-supplied array like the following:

const path = ["examples", param("exampleId"), "line", param<number>("lineNumber")] as const;

And I use this constant to generate a type for paths, which in this case would look like:

type Path = TypeMagic<typeof path>;
// type Path = ["examples", string, "line", number]

It would be nicer if I could generate this type instead:

type Path = TypeMagic<typeof path>;
// type Path = ["examples", exampleId: string, "line", lineNumber: number]

πŸ’» Use Cases

This came up while integrating TanStack Query into an application.

Since this is purely a documentation improvement, the workaround for the moment is to simply do without labels.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Oct 12, 2023
@RyanCavanaugh
Copy link
Member

I just wanted to say thank you for having a tuple label feature request that actually follows the spirit of tuple labels πŸ₯°

@jcalz
Copy link
Contributor

jcalz commented Oct 13, 2023

Cross-linking to #44939.

Personally I think it would be reasonable to also access labels as string literal types so you can transform labels (e.g., from [age: number] to [ageDefault: number]), as long as labels still have no effect on the assignability of the tuples themselves, and possibly even only have them readable from within a label-writing expression:

// Not wedded to this

// overwrite label if appearing in a tuple
type WithLabel<L extends string, T> = intrinsic;

// read tuple labels as string literal types, 
// but only within the L part of a WithLabel<L, T> expression
type Labels<T extends any[]> = intrinsic;

type A = [WithLabel<"abc", 123>, WithLabel<"def", 456>];
// type A = [abc: 123, def: 456];

type B = [WithLabel<Labels<A>[0], 789>];
// type B = [def: 789]; 

type Nope = Labels<A>;
// type Nope = [string, string]; // unobservable here

type DefaultLabels<T extends any[]> = { [I in keyof T]:
    WithLabel<`${Labels<T>[I]}Default`, T[I]> }

type C = DefaultLabels<[ghi: string, jkl: number, mno: boolean]>
// type C = [ghiDefault: string, jklDefault: number, mnoDefault: boolean]

@Andarist
Copy link
Contributor

After reading this, I feel like the original proposal is not that different from my experiments in #55452 . It just uses a different syntax - but the overall goals are the same: to provide extra documentation through dynamic labels without impacting assignability.

@tmm
Copy link

tmm commented Jan 17, 2024

Would love a feature like this! Shared a motivating example on the Design Meeting Notes for the experiment @Andarist is mentioning. #55511 (comment)

@Yuripetusko
Copy link

We also would greatly benefit from named/labeled tuples. Very useful when converting JSON ABI (which has option to provide more context to array elements, including names) to typescript (as per @tmm example). Very prone to bugs without this additional metadata for tuple elements

@yaindrop
Copy link

yaindrop commented May 17, 2025

This came up while integrating TanStack Query into an application.

I ended up here with exactly this same reason LOL

type Segmentize<URL extends string> = URL extends `/${infer Rest}`
  ? Segmentize<Rest>
  : URL extends `${infer Segment}/${infer Tail}`
    ? [...SegmentizeSegment<Segment>, ...Segmentize<Tail>]
    : SegmentizeSegment<URL>

type SegmentizeSegment<S extends string> = S extends `:${infer Param}` ? [Param: string] : [S]

// type Segments = ["foo", "bar", Param: string, "baz", Param: string, "some"]
type Segments = Segmentize<'/foo/bar/:barId/baz/:bazId/some'>

Here I'd like to have the "Param" label to be inferred from the string literal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

7 participants