microsoft / microsoft/TypeScript

[TS 4.2] Narrowing a union type is inconsistent using type guards on different member of union

Ouverte
#43,904 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Bug Domain: check: Control Flow
Langage dominant
Go
Étoiles
111k
Forks
14.4k
Merge moyen
1 j 19 h
PR mergées (30 j)
117

Description

Bug Report

🔎 Search Terms

narrowing union type

🕗 Version & Regression Information
  • This changed between versions 4.1.5 and 4.2.3
⏯ Playground Link

Playground link with relevant code

💻 Code
export type SuccessStatusCode = 200 | 201
export type FailureStatusCode = 400 | 401 | 402 | 403 | 500 | 502

interface HttpResponse<StatusCode extends SuccessStatusCode | FailureStatusCode> {
  statusCode: StatusCode
}

interface LegacyApiResponse extends Partial<{ [key: string]: unknown }> {
	statusCode?: never
}

type Success = HttpResponse<SuccessStatusCode> | LegacyApiResponse
type Failure = HttpResponse<FailureStatusCode>

type Result<S extends Success, F extends Failure = never> = S | F

declare function resultIsSuccess<S extends Success, F extends Failure>(r: Result<S, F>): r is S
declare function resultIsFailure<S extends Success, F extends Failure>(r: Result<S, F>): r is F

type TestResult = Result<{ success: true }, HttpResponse<403>>

declare const result: TestResult

export function test() {
  if (resultIsFailure(result)) {
    result // Inferred as HttpResponse<403>.
  } else {
    result // Inferred as { success: true }.
  }
}

export function test2() {
  if (resultIsSuccess(result)) {
    result // Inferred as { success: true }.
  } else {
    result // Cannot infer, stay as TestResult.
  }
}
🙁 Actual behavior

While test1 works fine, in test2, the else branch cannot narrow the type to HttpResponse<403>.

🙂 Expected behavior

test1 and test2 are just narrowing down result using complementary type guards, their behavior should be consistent.
And they are consistent in 4.1.

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

Commencez par la reproduction liée dans TypeScript Playground et comparez les guards complémentaires resultIsSuccess et resultIsFailure dans test() et test2(). Suivez la manière dont le vérificateur de types affine les branches else ; le travail est terminé lorsque les deux exemples affinent systématiquement le membre complémentaire de l’union comme prévu dans les versions de TypeScript signalées.

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

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

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