microsoft / microsoft/TypeScript
Pipe Operator instead of conditions and deep extends
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
- switch case
- switch case type level
- pipe operator ts
- pipe operator typescript
- avoid nested extends
- pipe ts type level
- type level switch
- switch typescript
### ✅ 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
My suggestion is to add a kind of idiomatic switch case for typescript types, where we could verify a list of `extends` without nesting.
**ERRATUM:** It does more than just adding syntax sugar to syntax, and behaves differently to a switch case. In this case, it determines a set of conditions that computes and returns the first found matching conditions. This way we could have more complex checking, instead of a simple "If Type T matches other Type U".
The example below does this. It not only checks "equality" and also does more things like calling other utility changes and then doing a condition check.
So, instead of a "switch case", it would likely feel closer to a syntax sugar to a sequence of "ifs".
Imagine a "replace" function that takes a text, find placeholders and provide an object with that placeholders as keys. This is how it can be achieved now:
```typescript
type Whitespace = '\n' | '\t' | ' ';
type TrimLeft =
T extends `${Whitespace}${infer S extends string}` ? TrimLeft : T;
type TrimRight =
T extends `${infer S extends string}${Whitespace}` ? TrimRight : T;
type Trim = TrimRight>;
type Equal = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
type IsJustString = Equal;
type Placeholders =
IsJustString extends true
? string
: Equal extends true
? Result
: T extends `${string}{{${infer P extends string}}}${infer Rest extends string}`
? Placeholders>
: Result;
export function withText(text: T) {
return {
replace: (contents: Record, string>) => {
let result: string = text;
for (const [key, value] of Object.entries(contents)) {
result = result.replace(`{{${key}}}`, value as string);
}
return result;
},
};
}
const helloWorld = withText("{{greeting}}, {{person}}").replace({
greeting: "Hello",
person: "World"
})
```
This is how it would look on my proposal:
```
type Whitespace = '\n' | '\t' | ' ';
type TrimLeft =
|> T extends `${Whitespace}${infer S extends string}`: TrimLeft,
|> T;
type TrimRight =
|> T extends `${infer S extends string}${Whitespace}`: TrimRight,
|> T;
type Trim = TrimRight>;
type Equal = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
type IsJustString = Equal;
type Placeholders =
|> IsJustString extends true: string,
|> Equal extends true: Result,
|> T extends `${string}{{${infer P extends string}}}${infer Rest extends string}`: Placeholders>,
|> Result;
export function withText(text: T) {
return {
replace: (contents: Record, string>) => {
let result: string = text;
for (const [key, value] of Object.entries(contents)) {
result = result.replace(`{{${key}}}`, value as string);
}
return result;
},
};
}
const helloWorld = withText("{{greeting}}, {{person}}").replace({
greeting: "Hello",
person: "World"
})
```
### 📃 Motivating Example
Sometimes nested extends can be too complicated to understand:
- The depth is is unmanageable
- Doesn't separate different concerns (are we still verifying possible values of T or are we doing something else?)
- Makes it hard to format
- Makes it hard to read
### 💻 Use Cases
1. What do you want to use this for?
Replace deep extends checks
2. What shortcomings exist with current approaches?
- Split into different types with different concers
- Format so that it looks like a "switch case"
3. What workarounds are you using in the meantime?
I have presented above
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
Das Issue nennt keine Repository-Dateien, Tests oder Einstiegspunkte. Beginne damit zu prüfen, wie TypeScript derzeit bedingte Typen parst und auswertet, und bestimme dann die erforderliche Syntax, das Verhalten der Typprüfung, Diagnosen und Kompatibilitätstests. Als erledigt würde ein akzeptiertes Design und ein Implementierungsplan gelten, nicht nur eine lokalisierte Änderung.
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
- 25/100