Skip to content

Assume arity of tuples when declared as literal #24350

Open
@aboyton

Description

@aboyton

Search Terms

tuples, length, arity

Suggestion

Now that #17765 is out I'm curious about if we could change the arity of tuples declared as literals. This was proposed as part of #16896 but I thought it might be better to pull this part out to have a discussion about this part of that proposal.

With fixed length tuples TypeScript allows you to convert [number, number] to number[] but not the other way around (which is great).

const foo = [1, 2];
const bar = [1, 2] as [number, number];

const foo2: [number, number] = foo;
const bar2: number[] = bar;

If you declare a constant such as foo above it would be nice if it would be nice if it would have the length as part of its type, that is, if foo was assumed to be of type [number, number] not number[].

This would have potential issues with mutable arrays allowing you to call push and pop although this isn't different to present and was discussed a bit in #6229.

const foo = [1, 2] as [number, number]; // After this proposal TypeScript would infer the type as `[number, number]` not `number[]`.
foo.push(3); // foo is of type `[number, number]` even though it now has 3 elements.
foo.splice(2); // And now it has 2 elements again.

Use Cases

When using a function such as fromPairs from lodash it requires that the type is a list of tuples. A simplified version is

function fromPairs<T>(values: [PropertyKey, T][]): { [key: string]: T } {
  return values.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
}

If I do

const foo = fromPairs(Object.entries({ a: 1, b: 2 }));

it works because the type passed into fromPairs is [string, number][], but if I try to say map the values to double their value I get a compile error:

const bar = fromPairs(Object.entries({ a: 1, b: 2 }).map(([key, value]) => [key, value * 2]));

as the parameter is of type (string | number)[][]

This can be fixed by going

const bar = fromPairs(Object.entries({ a: 1, b: 2 }).map(([key, value]) => [key, value * 2] as [string, number]));

but this is cumbersome.

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. new expression-level syntax)

Metadata

Metadata

Assignees

No one assigned

    Labels

    RevisitAn issue worth coming back toSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions