microsoft / microsoft/TypeScript

Pipe Operator instead of conditions and deep extends

Ouverte
#61,819 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Awaiting More Feedback Suggestion
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
2 j 4 h
PR mergées (30 j)
132

Description

### 🔍 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

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

L’issue ne nomme aucun fichier du dépôt, test ou point d’entrée. Commencez par examiner comment TypeScript analyse et évalue actuellement les types conditionnels, puis déterminez la syntaxe requise, le comportement de la vérification des types, les diagnostics et les tests de compatibilité. Le travail ne serait considéré comme terminé qu’avec une conception acceptée et un plan d’implémentation, et pas seulement une modification localisée.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
25/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.