Microsoft/TypeScript

Destructured tuple elements are no longer literals

Open

#37,427 opened on Mar 17, 2020

View on GitHub
 (0 comments) (2 reactions) (0 assignees)TypeScript (48,455 stars) (6,726 forks)batch import
BugDomain: Literal TypesHelp Wanted

Description

TypeScript Version: 3.9.0-dev.20200315

Search Terms:

  • tuple
  • destructuring
  • literal types
  • literals
  • inline
  • indexed access

Expected behavior:

When destructuring a tuple of array literals, destructured elements should preserve literal values.

Actual behavior:

Destructured elements are not literals.

Related Issues:

  • #32003
  • #31613

Code

If I create a tuple of literals:

declare function enumerate<T>(): <U extends T[]>(...elements: U) => U;

type Color = 'black' | 'white';

// $ExpectType ["black", "white"] ✅
const colors = enumerate<Color>()('black', 'white');

the accessed elements are also literals; regardless of whether I destructure them inline or read them in separate lines. That's good.

// $ExpectType ["black", "white"] ✅
const [primo, secundo] = colors;

// $ExpectType "black" ✅
const first = colors[0];

// $ExpectType "white" ✅
const second = colors[1];

However, when I do the same with a tuple returned by a function, their “literalness” is preserved only when the values are read using the square bracket notation:

// $ExpectType "black" ✅
const erste = enumerate<Color>()('black', 'white')[0];

// $ExpectType "white" ✅
const zweite = enumerate<Color>()('black', 'white')[1];

but not when the assignment happens via destructuring:

// $ExpectType ["black", "white"], received [Color, Color] ⛔️
const [one, two] = enumerate<Color>()('black', 'white');
"use strict";
// $ExpectType ["black", "white"] ✅
const colors = enumerate()('black', 'white');
// $ExpectType ["black", "white"] ✅
const [primo, secundo] = colors;
// $ExpectType "black" ✅
const first = colors[0];
// $ExpectType "white" ✅
const second = colors[1];
// $ExpectType "black" ✅
const erste = enumerate()('black', 'white')[0];
// $ExpectType "white" ✅
const zweite = enumerate()('black', 'white')[1];
// $ExpectType ["black", "white"], received [Color, Color] ⛔️
const [one, two] = enumerate()('black', 'white');

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": 2,
    "target": "ES2017",
    "jsx": "React",
    "module": "ESNext"
  }
}

Playground Link: Provided

Contributor guide