Skip to content

Proposal: strict and open-length tuple types #6229

Closed
@Igorbek

Description

@Igorbek

Update: converted to proposal.

Background

Currently, tuples are arrays that are restricted in minimum length, but not in maximum:

var t1: [number, number] = [1]; // this doesn't work
var t2: [number] = [1, 2]; // this works

This makes harder to predict types or errors in some scenarios:

var t1: [number, string];
var t2 = [...t1, ...t1]; // could be inferred to be [number, string, number, string], but must be inferred as [number, string] (now it's simply inferred as (number|string)[])

var t3: [number, string] = [1, "a"];
t3[2]; // ok, but must be an error

There also might be difficult to adopt variadic kinds, especially in type construction:

function f<...T>(...rest: [...T]): [...T, ...T] {
  var rest1: [...T] = [...rest, 1]; // it will be acceptable due to current rules
  return [...rest1, ...rest1]; // due to types it seems to be [...T, ...T], but actually is [...T, number, ...T, number]
}

Proposal

(1) Restrict tuple instance to match exact length

var t1: [number, string] = [1, "a"]; // ok
var t2: [number, string] = [1]; // error (existing)
var t3: [number, string] = [1, "a", "b"]; // error (new)

(2) Introduce open length tuple types

Open-length tuple types will be the same as tuple types are now.

var t1: [number, string, ...] = [1, "a", 2, "b"]; // same as current tuples are now
var t2: [number, string, ...(number|string|boolean)[]]; // explicitly type rest elements -- syntax option 1 -- consistent with rest parameters
var t3: [number, string, ...number|string]; // explicitly type rest elements -- syntax option 2

// strict tuple type can be implicitly converted to open length tuple type
var t4: [number, string, string];
var t5: [number, string, ...] = t4; // ok
var t6: [number, ...] = t4; // error, 'number|string' cannot be converted to 'number'
var t6: [number|string, ...] = t4; // ok
var t7: [number, ...(number|string)[]] = t4; // ok

(3) Improve contextual type inference for spread operators on tuples

var t1: [number, string];
var t2: [number, string, number, string] = [...t1, ...t1]; // it's proven now

var t3: [number, ...];
var t4: [string, ...];
var t4: [number, number|string, ...] = [...t3, ...t4]; // this also can be proven

Related issues

This addresses:

Disadvantages

This is definitely a breaking change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Breaking ChangeWould introduce errors in existing codeFixedA PR has been merged for this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions