microsoft / microsoft/TypeScript

Permit functions that return a value to also serve as a type guard

Ouverte
#31,376 2 commentaires 8 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Awaiting More Feedback Suggestion
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
1 j 19 h
PR mergées (30 j)
117

Description

Search Terms

Linear type, affine type, type guard

Suggestion

It would be very helpful to allow a function to serve as a type guard, but also return an unrelated value.

Use Cases

This can be used to express type changes as a result of mutating operations, covering some of the use cases of e.g. Rust's affine types. (See also #16148.)

Examples

Consider this example, compiled with --strictNullChecks:

type NonEmptyArray<T> = {
  pop(): T;
} & Array<T>;

function isNonEmpty<T>(array: Array<T>): array is NonEmptyArray<T>;
function isNonEmpty(array: Array<unknown>): boolean {
  return array.length > 0;
}

let array: string[] = ['element'];
if (isNonEmpty(array)) {  // Guard gives 'array' type NonEmptyArray<string>.
  const elem1: string = array.pop();  // Works. This is correct.
  const elem2: string = array.pop();  // Also works, but elem2 will be undefined at runtime!
}

We could make this correct if pop() could both return a value and behave as a type guard. This isn't great syntax, but nonetheless consider if this was supported:

type NonEmptyArray<T> = {
  pop(): T && this is Array<T>;
} & Array<T>;

function isNonEmpty<T>(array: Array<T>): array is NonEmptyArray<T>;
function isNonEmpty(array: Array<unknown>): boolean {
  return array.length > 0;
}

let array: string[] = ['element'];
if (isNonEmpty(array)) {  // Guard gives 'array' type NonEmptyArray<string>.
  const elem1: string = array.pop();  // Returns a string and gives 'array' type Array<string>.
  const elem2: string = array.pop();  // Doesn't compile; pop() returns 'string | undefined'!
}

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code

This can use a new, previously invalid syntax to avoid affecting any existing program.

  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)

There's no change in the code that's emitted; this feature would exist purely at the level of the type system.

I believe that it would. It seems to be aligned well, in particular, with "Statically identify constructs that are likely to be errors."

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

L’issue ne nomme aucun fichier source, test ou point d’entrée du compilateur. Commencez par localiser la gestion par TypeScript des prédicats de type et des types de retour, puis définissez la syntaxe acceptée et le comportement de narrowing, y compris l’exemple de pop() qui effectue une mutation, avec des tests du compilateur couvrant les nouveaux cas et les cas invalides.

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.