Microsoft/TypeScript
View on GitHubDestructured tuple elements are no longer literals
Open
#37,427 opened on Mar 17, 2020
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