diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8797dbbf80137..109f29c7d2356 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -38753,7 +38753,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 9701d6aeed82f..abb653265f3d9 100644 --- a/tests/baselines/reference/inferTypePredicates.errors.txt +++ b/tests/baselines/reference/inferTypePredicates.errors.txt @@ -343,4 +343,27 @@ inferTypePredicates.ts(205,7): error TS2741: Property 'z' is missing in type 'C1 const rv = x === ""; return rv satisfies boolean; } + + // 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 725c3eb6b0b34..a24586a228653 100644 --- a/tests/baselines/reference/inferTypePredicates.js +++ b/tests/baselines/reference/inferTypePredicates.js @@ -289,6 +289,29 @@ function isEmptyString(x: unknown) { const rv = x === ""; return rv satisfies boolean; } + +// 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] @@ -554,6 +577,15 @@ function isEmptyString(x) { var rv = x === ""; return rv; } +function isAnimal(something) { + return something.breath; +} +function positive(t) { + return isAnimal(t); +} +function negative(t) { + return !isAnimal(t); +} //// [inferTypePredicates.d.ts] @@ -648,3 +680,13 @@ declare const foobarPred: (fb: typeof foobar) => fb is { }; declare const arrTest: Array; declare function isEmptyString(x: unknown): x is ""; +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 aec451e86fd4b..59658e8b9fa8f 100644 --- a/tests/baselines/reference/inferTypePredicates.symbols +++ b/tests/baselines/reference/inferTypePredicates.symbols @@ -802,3 +802,58 @@ function isEmptyString(x: unknown) { >rv : Symbol(rv, Decl(inferTypePredicates.ts, 285, 7)) } +// https://github.com/microsoft/TypeScript/issues/58996 +type Animal = { +>Animal : Symbol(Animal, Decl(inferTypePredicates.ts, 287, 1)) + + breath: true, +>breath : Symbol(breath, Decl(inferTypePredicates.ts, 290, 15)) + +}; + +type Rock = { +>Rock : Symbol(Rock, Decl(inferTypePredicates.ts, 292, 2)) + + breath: false, +>breath : Symbol(breath, Decl(inferTypePredicates.ts, 294, 13)) + +}; + +type Something = Animal | Rock; +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 296, 2)) +>Animal : Symbol(Animal, Decl(inferTypePredicates.ts, 287, 1)) +>Rock : Symbol(Rock, Decl(inferTypePredicates.ts, 292, 2)) + +function isAnimal(something: Something): something is Animal { +>isAnimal : Symbol(isAnimal, Decl(inferTypePredicates.ts, 298, 31)) +>something : Symbol(something, Decl(inferTypePredicates.ts, 300, 18)) +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 296, 2)) +>something : Symbol(something, Decl(inferTypePredicates.ts, 300, 18)) +>Animal : Symbol(Animal, Decl(inferTypePredicates.ts, 287, 1)) + + return something.breath +>something.breath : Symbol(breath, Decl(inferTypePredicates.ts, 290, 15), Decl(inferTypePredicates.ts, 294, 13)) +>something : Symbol(something, Decl(inferTypePredicates.ts, 300, 18)) +>breath : Symbol(breath, Decl(inferTypePredicates.ts, 290, 15), Decl(inferTypePredicates.ts, 294, 13)) +} + +function positive(t: Something) { +>positive : Symbol(positive, Decl(inferTypePredicates.ts, 302, 1)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 304, 18)) +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 296, 2)) + + return isAnimal(t) +>isAnimal : Symbol(isAnimal, Decl(inferTypePredicates.ts, 298, 31)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 304, 18)) +} + +function negative(t: Something) { +>negative : Symbol(negative, Decl(inferTypePredicates.ts, 306, 1)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 308, 18)) +>Something : Symbol(Something, Decl(inferTypePredicates.ts, 296, 2)) + + return !isAnimal(t) +>isAnimal : Symbol(isAnimal, Decl(inferTypePredicates.ts, 298, 31)) +>t : Symbol(t, Decl(inferTypePredicates.ts, 308, 18)) +} + diff --git a/tests/baselines/reference/inferTypePredicates.types b/tests/baselines/reference/inferTypePredicates.types index 326617e83ba05..a2837fd5d91c7 100644 --- a/tests/baselines/reference/inferTypePredicates.types +++ b/tests/baselines/reference/inferTypePredicates.types @@ -1707,3 +1707,79 @@ function isEmptyString(x: unknown) { > : ^^^^^^^ } +// 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 bb8e6132f4279..960022e3e7cb3 100644 --- a/tests/cases/compiler/inferTypePredicates.ts +++ b/tests/cases/compiler/inferTypePredicates.ts @@ -289,3 +289,26 @@ function isEmptyString(x: unknown) { const rv = x === ""; return rv satisfies boolean; } + +// 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) +}