microsoft / microsoft/TypeScript
Tuples: maintaining type-param in the type of it's items
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.3k
- Ø Merge
- 2 T. 4 Std.
- Gemergte PRs (30 T.)
- 132
Beschreibung
### 🔍 Search Terms
for-of, T[number], tuple (I couldn't find more specific search terms).
### ✅ Viability Checklist
- [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [x] This wouldn't change the runtime behavior of existing JavaScript code
- [x] This could be implemented without emitting different JS based on the types of the expressions
- [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- [x] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- [x] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
### ⭐ Suggestion
When a function takes an array/tuple as a type-parameter, e.g.
```ts
function foo(items: T): void;
```
When accessing the items of this array (`items[0]`), they are "resolved" to the type defined for the generic, e.g., `unknown` in this example, but should be kept unresolved so that they show up as `T[number] | undefined`.
This becomes an issue once a function takes more than one array like this, for example, if it wants to use the tuple/array shape as a param in the output. This can lead to real runtime errors where TypeScript isn't providing enough safety.
This is also relevant for for-of loops iterating over items
```ts
for (const item of items) {
console.log(item);
// ^? unknown, can be T[number]
}
```
### 📃 Motivating Example
The following example passes typescript checking but fails in runtime and throws exceptions when trying to access methods of strings on a number, and vice-versa.
```ts
type DoubleMap<
T extends readonly unknown[],
S extends readonly unknown[],
RT,
RS,
> = [...{ [I in keyof T]: RT }, ...{ [I in keyof S]: RS }];
function doubleMap<
T extends readonly unknown[],
S extends readonly unknown[],
RT,
RS,
>(
t: T,
s: S,
mapperT: (item: T[number]) => RT,
mapperS: (item: S[number]) => RS,
): DoubleMap {
const output: (T[number] | S[number])[] = [];
for (const itemT of t) {
// Oops, we got the mappers wrong, we are calling mapperS with an item from T
output.push(mapperS(itemT));
}
for (const itemS of s) {
// ...And here we are calling mapperT with an item from S
output.push(mapperT(itemS));
}
// @ts-expect-error [ts2322] -- TypeScript can't tell we finished building the output, this is fine...
return output;
}
const result = doubleMap(
// ^? [boolean, boolean, boolean, number, number, number]
["a", "b", "c"] as const,
[1, 2, 3] as const,
(item) => item.startsWith("a"),
(item) => item.toPrecision(1),
);
```
https://www.typescriptlang.org/play/?noUncheckedIndexedAccess=true&noUnusedLocals=true&noUnusedParameters=true&noPropertyAccessFromIndexSignature=true&noImplicitOverride=true&noFallthroughCasesInSwitch=true&exactOptionalPropertyTypes=true#code/C4TwDgpgBAIg9gVwEYBsIFkCGYA8AoKKAFSggA9gIA7AEwGcoAnCTGuKlEKBKgayrgB3KgG0AugBoCUAMqkK1ekxZsOXHvyGjJ0gEpEphXTKkA+KAF4oIgHR2A3tYCSUAJZUovCCDgAzYmIAXFD6UAC+ElB2No4iLu6e3n6yQSFyYWIA3Hh4vjwAxsCu7FBsyGhYuNIk5JS0DMys7JzcfALC4oay8nVKjaotGu3aXfqjJnimABTSwMEG0nTBE4QAttiQjETBU66Uq-MiVAirSBCMYgCUluZj0utgmzI7exAHskcnZxfXFrcTl2C8HKGGwOAMskiYzS5ns0ny7DowCgiGAYAQcygUyIn1O5zEUAAPh9jnifuJLNYsjlCL44IwsQiqEi3PsSMlgNc4YRCAB6XlQADycDAdEigmgAHM4MjgAALaAPTYMQSMdiS8XQTDMKD5TAoFDuSVQJXnOSCPZyqCYDyvVZQXxq+1EaSEVHo4A2dF0OVTU2MGS7NmXS7ZQhhGkO+mMxHIu1yZJ0LmuqD8qJ2ACCtCgCp1EutOr1BqNJo25xIFvl1tt+wdTtkKfdGK9CB9frLWyDbxkIbD4UjaYAAsA6ABaciQQrjxhqhkiEcAJgAzAuFwTR6PiOAIDJ8oxXGBkXqqAByWUQA1QfO+dyuH0QGhQJAIVwoGgl+XQJvASLyu9uBgbyoCBomkZhgAQRgPG-bIIzwJkWWYOgEBQZErDKVBQTAGY+QFKAAD0AH5pBEAAiTBSMiUikEoqBSPyUiCUwBgEJ-EiAEZIgXSIlyYljYy6LtVl+cw7RsJFtRHAB1S0pnI0jLkEu0RNZN4bGAOAAAVmHyO9iioKZ2MUvBQzwIA
Live example:
https://codesandbox.io/p/sandbox/tgr8pm
### 💻 Use Cases
1. What do you want to use this for?
2. What shortcomings exist with current approaches?
3. What workarounds are you using in the meantime?
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne mit dem motivierenden doubleMap-Beispiel und dem verknüpften TypeScript Playground und untersuche anschließend, wie der indizierte Zugriff auf generische Tupel und die for-of-Iteration derzeit geprüft werden. Als erledigt gilt die Aufgabe, wenn die vertauschten Mapper-Aufrufe abgelehnt werden, während gültige Verwendungen von Tupeln und Arrays weiterhin die passenden Elementtypen T[number] oder S[number] beibehalten.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- compilers
- Issue-Typ
- Feature
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 35/100