Skip to content

Commit 42a215c

Browse files
authored
Fixed type predicate inference for discriminated union parameters (#57952)
1 parent 4cedfe4 commit 42a215c

File tree

6 files changed

+133
-3
lines changed

6 files changed

+133
-3
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37690,8 +37690,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3769037690
{ flags: FlowFlags.Start };
3769137691
const trueCondition: FlowCondition = {
3769237692
flags: FlowFlags.TrueCondition,
37693-
node: expr,
3769437693
antecedent,
37694+
node: expr,
3769537695
};
3769637696

3769737697
const trueType = getFlowTypeOfReference(param.name, initType, initType, func, trueCondition);
@@ -37700,10 +37700,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3770037700
// "x is T" means that x is T if and only if it returns true. If it returns false then x is not T.
3770137701
// 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`.
3770237702
const falseCondition: FlowCondition = {
37703-
...trueCondition,
3770437703
flags: FlowFlags.FalseCondition,
37704+
antecedent,
37705+
node: expr,
3770537706
};
37706-
const falseSubtype = getFlowTypeOfReference(param.name, trueType, trueType, func, falseCondition);
37707+
const falseSubtype = getFlowTypeOfReference(param.name, initType, trueType, func, falseCondition);
3770737708
return falseSubtype.flags & TypeFlags.Never ? trueType : undefined;
3770837709
}
3770937710

tests/baselines/reference/inferTypePredicates.errors.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,14 @@ inferTypePredicates.ts(205,7): error TS2741: Property 'z' is missing in type 'C1
315315
function inferWithRest(x: string | null, ...f: ["a", "b"]) {
316316
return typeof x === 'string';
317317
}
318+
319+
// https://github.com/microsoft/TypeScript/issues/57947
320+
declare const foobar:
321+
| { type: "foo"; foo: number }
322+
| { type: "bar"; bar: string };
323+
324+
const foobarPred = (fb: typeof foobar) => fb.type === "foo";
325+
if (foobarPred(foobar)) {
326+
foobar.foo;
327+
}
318328

tests/baselines/reference/inferTypePredicates.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,16 @@ const noInferenceFromImpossibleRest = (...f: []) => typeof f === "undefined";
269269
function inferWithRest(x: string | null, ...f: ["a", "b"]) {
270270
return typeof x === 'string';
271271
}
272+
273+
// https://github.com/microsoft/TypeScript/issues/57947
274+
declare const foobar:
275+
| { type: "foo"; foo: number }
276+
| { type: "bar"; bar: string };
277+
278+
const foobarPred = (fb: typeof foobar) => fb.type === "foo";
279+
if (foobarPred(foobar)) {
280+
foobar.foo;
281+
}
272282

273283

274284
//// [inferTypePredicates.js]
@@ -524,6 +534,10 @@ function inferWithRest(x) {
524534
}
525535
return typeof x === 'string';
526536
}
537+
var foobarPred = function (fb) { return fb.type === "foo"; };
538+
if (foobarPred(foobar)) {
539+
foobar.foo;
540+
}
527541

528542

529543
//// [inferTypePredicates.d.ts]
@@ -605,3 +619,14 @@ declare function narrowFromAny(x: any): x is number;
605619
declare const noInferenceFromRest: (f_0: "a" | "b") => boolean;
606620
declare const noInferenceFromImpossibleRest: () => boolean;
607621
declare function inferWithRest(x: string | null, ...f: ["a", "b"]): x is string;
622+
declare const foobar: {
623+
type: "foo";
624+
foo: number;
625+
} | {
626+
type: "bar";
627+
bar: string;
628+
};
629+
declare const foobarPred: (fb: typeof foobar) => fb is {
630+
type: "foo";
631+
foo: number;
632+
};

tests/baselines/reference/inferTypePredicates.symbols

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,3 +747,33 @@ function inferWithRest(x: string | null, ...f: ["a", "b"]) {
747747
>x : Symbol(x, Decl(inferTypePredicates.ts, 265, 23))
748748
}
749749

750+
// https://github.com/microsoft/TypeScript/issues/57947
751+
declare const foobar:
752+
>foobar : Symbol(foobar, Decl(inferTypePredicates.ts, 270, 13))
753+
754+
| { type: "foo"; foo: number }
755+
>type : Symbol(type, Decl(inferTypePredicates.ts, 271, 5))
756+
>foo : Symbol(foo, Decl(inferTypePredicates.ts, 271, 18))
757+
758+
| { type: "bar"; bar: string };
759+
>type : Symbol(type, Decl(inferTypePredicates.ts, 272, 5))
760+
>bar : Symbol(bar, Decl(inferTypePredicates.ts, 272, 18))
761+
762+
const foobarPred = (fb: typeof foobar) => fb.type === "foo";
763+
>foobarPred : Symbol(foobarPred, Decl(inferTypePredicates.ts, 274, 5))
764+
>fb : Symbol(fb, Decl(inferTypePredicates.ts, 274, 20))
765+
>foobar : Symbol(foobar, Decl(inferTypePredicates.ts, 270, 13))
766+
>fb.type : Symbol(type, Decl(inferTypePredicates.ts, 271, 5), Decl(inferTypePredicates.ts, 272, 5))
767+
>fb : Symbol(fb, Decl(inferTypePredicates.ts, 274, 20))
768+
>type : Symbol(type, Decl(inferTypePredicates.ts, 271, 5), Decl(inferTypePredicates.ts, 272, 5))
769+
770+
if (foobarPred(foobar)) {
771+
>foobarPred : Symbol(foobarPred, Decl(inferTypePredicates.ts, 274, 5))
772+
>foobar : Symbol(foobar, Decl(inferTypePredicates.ts, 270, 13))
773+
774+
foobar.foo;
775+
>foobar.foo : Symbol(foo, Decl(inferTypePredicates.ts, 271, 18))
776+
>foobar : Symbol(foobar, Decl(inferTypePredicates.ts, 270, 13))
777+
>foo : Symbol(foo, Decl(inferTypePredicates.ts, 271, 18))
778+
}
779+

tests/baselines/reference/inferTypePredicates.types

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,3 +1595,57 @@ function inferWithRest(x: string | null, ...f: ["a", "b"]) {
15951595
> : ^^^^^^^^
15961596
}
15971597

1598+
// https://github.com/microsoft/TypeScript/issues/57947
1599+
declare const foobar:
1600+
>foobar : { type: "foo"; foo: number; } | { type: "bar"; bar: string; }
1601+
> : ^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^ ^^^
1602+
1603+
| { type: "foo"; foo: number }
1604+
>type : "foo"
1605+
> : ^^^^^
1606+
>foo : number
1607+
> : ^^^^^^
1608+
1609+
| { type: "bar"; bar: string };
1610+
>type : "bar"
1611+
> : ^^^^^
1612+
>bar : string
1613+
> : ^^^^^^
1614+
1615+
const foobarPred = (fb: typeof foobar) => fb.type === "foo";
1616+
>foobarPred : (fb: typeof foobar) => fb is { type: "foo"; foo: number; }
1617+
> : ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1618+
>(fb: typeof foobar) => fb.type === "foo" : (fb: typeof foobar) => fb is { type: "foo"; foo: number; }
1619+
> : ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1620+
>fb : { type: "foo"; foo: number; } | { type: "bar"; bar: string; }
1621+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1622+
>foobar : { type: "foo"; foo: number; } | { type: "bar"; bar: string; }
1623+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1624+
>fb.type === "foo" : boolean
1625+
> : ^^^^^^^
1626+
>fb.type : "bar" | "foo"
1627+
> : ^^^^^^^^^^^^^
1628+
>fb : { type: "foo"; foo: number; } | { type: "bar"; bar: string; }
1629+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1630+
>type : "bar" | "foo"
1631+
> : ^^^^^^^^^^^^^
1632+
>"foo" : "foo"
1633+
> : ^^^^^
1634+
1635+
if (foobarPred(foobar)) {
1636+
>foobarPred(foobar) : boolean
1637+
> : ^^^^^^^
1638+
>foobarPred : (fb: { type: "foo"; foo: number; } | { type: "bar"; bar: string; }) => fb is { type: "foo"; foo: number; }
1639+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1640+
>foobar : { type: "foo"; foo: number; } | { type: "bar"; bar: string; }
1641+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1642+
1643+
foobar.foo;
1644+
>foobar.foo : number
1645+
> : ^^^^^^
1646+
>foobar : { type: "foo"; foo: number; }
1647+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1648+
>foo : number
1649+
> : ^^^^^^
1650+
}
1651+

tests/cases/compiler/inferTypePredicates.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,13 @@ const noInferenceFromImpossibleRest = (...f: []) => typeof f === "undefined";
269269
function inferWithRest(x: string | null, ...f: ["a", "b"]) {
270270
return typeof x === 'string';
271271
}
272+
273+
// https://github.com/microsoft/TypeScript/issues/57947
274+
declare const foobar:
275+
| { type: "foo"; foo: number }
276+
| { type: "bar"; bar: string };
277+
278+
const foobarPred = (fb: typeof foobar) => fb.type === "foo";
279+
if (foobarPred(foobar)) {
280+
foobar.foo;
281+
}

0 commit comments

Comments
 (0)