From 407687affbb0252b884041d5c45a0f6e33a73658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mar=C5=A1=C3=A1lek?= Date: Sat, 6 Jul 2024 02:19:33 +0200 Subject: [PATCH] fixes #58996 --- src/compiler/checker.ts | 2 +- .../reference/inferTypePredicates.errors.txt | 24 +++++- .../reference/inferTypePredicates.js | 43 ++++++++++- .../reference/inferTypePredicates.symbols | 54 +++++++++++++ .../reference/inferTypePredicates.types | 75 +++++++++++++++++++ tests/cases/compiler/inferTypePredicates.ts | 23 ++++++ 6 files changed, 218 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 770e1a7c1c60a..73ec4d72d3215 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -38409,7 +38409,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // "x is T" means that x is T if and only if it returns true. If it returns false then x is not T. // This means that if the function is called with an argument of type trueType, there can't be anything left in the `else` branch. It must reduce to `never`. const falseCondition = createFlowNode(FlowFlags.FalseCondition, expr, antecedent); - const falseSubtype = getFlowTypeOfReference(param.name, initType, trueType, func, falseCondition); + const falseSubtype = getReducedType(getFlowTypeOfReference(param.name, initType, trueType, func, falseCondition)); return falseSubtype.flags & TypeFlags.Never ? trueType : undefined; } diff --git a/tests/baselines/reference/inferTypePredicates.errors.txt b/tests/baselines/reference/inferTypePredicates.errors.txt index e61c1cb72beef..22ffabd1405c6 100644 --- a/tests/baselines/reference/inferTypePredicates.errors.txt +++ b/tests/baselines/reference/inferTypePredicates.errors.txt @@ -325,4 +325,26 @@ inferTypePredicates.ts(205,7): error TS2741: Property 'z' is missing in type 'C1 if (foobarPred(foobar)) { foobar.foo; } - \ No newline at end of file + + // https://github.com/microsoft/TypeScript/issues/58996 + type Animal = { + breath: true, + }; + + type Rock = { + breath: false, + }; + + type Something = Animal | Rock; + + function isAnimal(something: Something): something is Animal { + return something.breath + } + + function positive(t: Something) { + return isAnimal(t) + } + + function negative(t: Something) { + return !isAnimal(t) + } \ No newline at end of file diff --git a/tests/baselines/reference/inferTypePredicates.js b/tests/baselines/reference/inferTypePredicates.js index b5802c0e50a99..e9bea2861f5c3 100644 --- a/tests/baselines/reference/inferTypePredicates.js +++ b/tests/baselines/reference/inferTypePredicates.js @@ -279,7 +279,29 @@ const foobarPred = (fb: typeof foobar) => fb.type === "foo"; if (foobarPred(foobar)) { foobar.foo; } - + +// https://github.com/microsoft/TypeScript/issues/58996 +type Animal = { + breath: true, +}; + +type Rock = { + breath: false, +}; + +type Something = Animal | Rock; + +function isAnimal(something: Something): something is Animal { + return something.breath +} + +function positive(t: Something) { + return isAnimal(t) +} + +function negative(t: Something) { + return !isAnimal(t) +} //// [inferTypePredicates.js] // https://github.com/microsoft/TypeScript/issues/16069 @@ -538,6 +560,15 @@ var foobarPred = function (fb) { return fb.type === "foo"; }; if (foobarPred(foobar)) { foobar.foo; } +function isAnimal(something) { + return something.breath; +} +function positive(t) { + return isAnimal(t); +} +function negative(t) { + return !isAnimal(t); +} //// [inferTypePredicates.d.ts] @@ -630,3 +661,13 @@ declare const foobarPred: (fb: typeof foobar) => fb is { type: "foo"; foo: number; }; +type Animal = { + breath: true; +}; +type Rock = { + breath: false; +}; +type Something = Animal | Rock; +declare function isAnimal(something: Something): something is Animal; +declare function positive(t: Something): t is Animal; +declare function negative(t: Something): t is Rock; diff --git a/tests/baselines/reference/inferTypePredicates.symbols b/tests/baselines/reference/inferTypePredicates.symbols index 8fd879787c205..44fcd6081ff58 100644 --- a/tests/baselines/reference/inferTypePredicates.symbols +++ b/tests/baselines/reference/inferTypePredicates.symbols @@ -777,3 +777,57 @@ if (foobarPred(foobar)) { >foo : Symbol(foo, Decl(inferTypePredicates.ts, 271, 18)) } +// https://github.com/microsoft/TypeScript/issues/58996 +type Animal = { +>Animal : Symbol(Animal, Decl(inferTypePredicates.ts, 277, 1)) + + breath: true, +>breath : Symbol(breath, Decl(inferTypePredicates.ts, 280, 15)) + +}; + +type Rock = { +>Rock : Symbol(Rock, Decl(inferTypePredicates.ts, 282, 2)) + + breath: false, +>breath : Symbol(breath, Decl(inferTypePredicates.ts, 284, 13)) + +}; + +type Something = Animal | Rock; +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 286, 2)) +>Animal : Symbol(Animal, Decl(inferTypePredicates.ts, 277, 1)) +>Rock : Symbol(Rock, Decl(inferTypePredicates.ts, 282, 2)) + +function isAnimal(something: Something): something is Animal { +>isAnimal : Symbol(isAnimal, Decl(inferTypePredicates.ts, 288, 31)) +>something : Symbol(something, Decl(inferTypePredicates.ts, 290, 18)) +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 286, 2)) +>something : Symbol(something, Decl(inferTypePredicates.ts, 290, 18)) +>Animal : Symbol(Animal, Decl(inferTypePredicates.ts, 277, 1)) + + return something.breath +>something.breath : Symbol(breath, Decl(inferTypePredicates.ts, 280, 15), Decl(inferTypePredicates.ts, 284, 13)) +>something : Symbol(something, Decl(inferTypePredicates.ts, 290, 18)) +>breath : Symbol(breath, Decl(inferTypePredicates.ts, 280, 15), Decl(inferTypePredicates.ts, 284, 13)) +} + +function positive(t: Something) { +>positive : Symbol(positive, Decl(inferTypePredicates.ts, 292, 1)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 294, 18)) +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 286, 2)) + + return isAnimal(t) +>isAnimal : Symbol(isAnimal, Decl(inferTypePredicates.ts, 288, 31)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 294, 18)) +} + +function negative(t: Something) { +>negative : Symbol(negative, Decl(inferTypePredicates.ts, 296, 1)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 298, 18)) +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 286, 2)) + + return !isAnimal(t) +>isAnimal : Symbol(isAnimal, Decl(inferTypePredicates.ts, 288, 31)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 298, 18)) +} diff --git a/tests/baselines/reference/inferTypePredicates.types b/tests/baselines/reference/inferTypePredicates.types index 20eaa4a583148..c3f818a3d442e 100644 --- a/tests/baselines/reference/inferTypePredicates.types +++ b/tests/baselines/reference/inferTypePredicates.types @@ -1649,3 +1649,78 @@ if (foobarPred(foobar)) { > : ^^^^^^ } +// https://github.com/microsoft/TypeScript/issues/58996 +type Animal = { +>Animal : Animal +> : ^^^^^^ + + breath: true, +>breath : true +> : ^^^^ +>true : true +> : ^^^^ + +}; + +type Rock = { +>Rock : Rock +> : ^^^^ + + breath: false, +>breath : false +> : ^^^^^ +>false : false +> : ^^^^^ + +}; + +type Something = Animal | Rock; +>Something : Something +> : ^^^^^^^^^ + +function isAnimal(something: Something): something is Animal { +>isAnimal : (something: Something) => something is Animal +> : ^ ^^ ^^^^^ +>something : Something +> : ^^^^^^^^^ + + return something.breath +>something.breath : boolean +> : ^^^^^^^ +>something : Something +> : ^^^^^^^^^ +>breath : boolean +> : ^^^^^^^ +} + +function positive(t: Something) { +>positive : (t: Something) => t is Animal +> : ^ ^^ ^^^^^^^^^^^^^^^^ +>t : Something +> : ^^^^^^^^^ + + return isAnimal(t) +>isAnimal(t) : boolean +> : ^^^^^^^ +>isAnimal : (something: Something) => something is Animal +> : ^ ^^ ^^^^^ +>t : Something +> : ^^^^^^^^^ +} + +function negative(t: Something) { +>negative : (t: Something) => t is Rock +> : ^ ^^ ^^^^^^^^^^^^^^ +>t : Something +> : ^^^^^^^^^ + + return !isAnimal(t) +>!isAnimal(t) : boolean +> : ^^^^^^^ +>isAnimal(t) : boolean +> : ^^^^^^^ +>isAnimal : (something: Something) => something is Animal +> : ^ ^^ ^^^^^ +>t : Something +> : ^^^^^^^^^ +} diff --git a/tests/cases/compiler/inferTypePredicates.ts b/tests/cases/compiler/inferTypePredicates.ts index 9b996ee8c8414..44641a2c1f9d3 100644 --- a/tests/cases/compiler/inferTypePredicates.ts +++ b/tests/cases/compiler/inferTypePredicates.ts @@ -279,3 +279,26 @@ const foobarPred = (fb: typeof foobar) => fb.type === "foo"; if (foobarPred(foobar)) { foobar.foo; } + +// https://github.com/microsoft/TypeScript/issues/58996 +type Animal = { + breath: true, +}; + +type Rock = { + breath: false, +}; + +type Something = Animal | Rock; + +function isAnimal(something: Something): something is Animal { + return something.breath +} + +function positive(t: Something) { + return isAnimal(t) +} + +function negative(t: Something) { + return !isAnimal(t) +} \ No newline at end of file