From 8b3588d749c4821f6ace5d5f081754fcae039a0f Mon Sep 17 00:00:00 2001 From: Erik Brinkman Date: Mon, 3 May 2021 00:06:55 -0400 Subject: [PATCH] Fix contextual discrimination for omitted members In short, the fix I submitted looked at the union ofproperties, but it really should have looked at the intersection. Two sytlistic notes. I couldn't find the best way to get the unique strings of an array like `[...new Set()]` would, so I created a small helper function, but didn't put it in a great place. Also, before the second concatenated array of discriminators at least matched the first in complexity, but now it's much worse. I don't think that section is particularly easy to read, but I also don't see a significantly reusable part. fixes #41759 --- src/compiler/checker.ts | 25 +++++- .../discriminantPropertyInference.js | 16 +++- .../discriminantPropertyInference.symbols | 73 ++++++++++++------ .../discriminantPropertyInference.types | 30 +++++++- .../tsxDiscriminantPropertyInference.js | 15 +++- .../tsxDiscriminantPropertyInference.symbols | 77 +++++++++++++------ .../tsxDiscriminantPropertyInference.types | 43 +++++++++-- .../compiler/discriminantPropertyInference.ts | 12 ++- .../tsxDiscriminantPropertyInference.tsx | 13 +++- 9 files changed, 237 insertions(+), 67 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4d95f128b1a0d..ecc0ad0eaba2c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25378,6 +25378,13 @@ namespace ts { return false; } + function uniqueStrings(strings: readonly __String[]): __String[] { + const unique = new Set(strings); + const result: __String[] = []; + unique.forEach(str => result.push(str)); + return result; + } + function discriminateContextualTypeByObjectMembers(node: ObjectLiteralExpression, contextualType: UnionType) { return getMatchingUnionConstituentForObjectLiteral(contextualType, node) || discriminateTypeByDiscriminableItems(contextualType, concatenate( @@ -25386,8 +25393,13 @@ namespace ts { prop => ([() => getContextFreeTypeOfExpression((prop as PropertyAssignment).initializer), prop.symbol.escapedName] as [() => Type, __String]) ), map( - filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), - s => [() => undefinedType, s.escapedName] as [() => Type, __String] + uniqueStrings(flatMap(contextualType.types, memberType => + map( + filter(getPropertiesOfType(memberType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), + s => s.escapedName + ) + )), + name => [() => undefinedType, name] as [() => Type, __String] ) ), isTypeAssignableTo, @@ -25403,8 +25415,13 @@ namespace ts { prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => checkExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as [() => Type, __String]) ), map( - filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), - s => [() => undefinedType, s.escapedName] as [() => Type, __String] + uniqueStrings(flatMap(contextualType.types, memberType => + map( + filter(getPropertiesOfType(memberType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), + s => s.escapedName + ) + )), + name => [() => undefinedType, name] as [() => Type, __String] ) ), isTypeAssignableTo, diff --git a/tests/baselines/reference/discriminantPropertyInference.js b/tests/baselines/reference/discriminantPropertyInference.js index 96f6a106a1136..e65bf3869b0bc 100644 --- a/tests/baselines/reference/discriminantPropertyInference.js +++ b/tests/baselines/reference/discriminantPropertyInference.js @@ -11,7 +11,9 @@ type DiscriminatorFalse = { cb: (x: number) => void; } -type Props = DiscriminatorTrue | DiscriminatorFalse; +type Unrelated = { + val: number; +} declare function f(options: DiscriminatorTrue | DiscriminatorFalse): any; @@ -37,6 +39,14 @@ f({ f({ cb: n => n.toFixed() }); + + +declare function g(options: DiscriminatorTrue | DiscriminatorFalse | Unrelated): any; + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +g({ + cb: n => n.toFixed() +}); //// [discriminantPropertyInference.js] @@ -60,3 +70,7 @@ f({ f({ cb: function (n) { return n.toFixed(); } }); +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +g({ + cb: function (n) { return n.toFixed(); } +}); diff --git a/tests/baselines/reference/discriminantPropertyInference.symbols b/tests/baselines/reference/discriminantPropertyInference.symbols index 1908bdd984321..938ce86b0c20c 100644 --- a/tests/baselines/reference/discriminantPropertyInference.symbols +++ b/tests/baselines/reference/discriminantPropertyInference.symbols @@ -23,74 +23,97 @@ type DiscriminatorFalse = { >x : Symbol(x, Decl(discriminantPropertyInference.ts, 9, 9)) } -type Props = DiscriminatorTrue | DiscriminatorFalse; ->Props : Symbol(Props, Decl(discriminantPropertyInference.ts, 10, 1)) ->DiscriminatorTrue : Symbol(DiscriminatorTrue, Decl(discriminantPropertyInference.ts, 0, 0)) ->DiscriminatorFalse : Symbol(DiscriminatorFalse, Decl(discriminantPropertyInference.ts, 5, 1)) +type Unrelated = { +>Unrelated : Symbol(Unrelated, Decl(discriminantPropertyInference.ts, 10, 1)) + + val: number; +>val : Symbol(val, Decl(discriminantPropertyInference.ts, 12, 18)) +} declare function f(options: DiscriminatorTrue | DiscriminatorFalse): any; ->f : Symbol(f, Decl(discriminantPropertyInference.ts, 12, 52)) ->options : Symbol(options, Decl(discriminantPropertyInference.ts, 14, 19)) +>f : Symbol(f, Decl(discriminantPropertyInference.ts, 14, 1)) +>options : Symbol(options, Decl(discriminantPropertyInference.ts, 16, 19)) >DiscriminatorTrue : Symbol(DiscriminatorTrue, Decl(discriminantPropertyInference.ts, 0, 0)) >DiscriminatorFalse : Symbol(DiscriminatorFalse, Decl(discriminantPropertyInference.ts, 5, 1)) // simple inference f({ ->f : Symbol(f, Decl(discriminantPropertyInference.ts, 12, 52)) +>f : Symbol(f, Decl(discriminantPropertyInference.ts, 14, 1)) disc: true, ->disc : Symbol(disc, Decl(discriminantPropertyInference.ts, 17, 3)) +>disc : Symbol(disc, Decl(discriminantPropertyInference.ts, 19, 3)) cb: s => parseInt(s) ->cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 18, 15)) ->s : Symbol(s, Decl(discriminantPropertyInference.ts, 19, 7)) +>cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 20, 15)) +>s : Symbol(s, Decl(discriminantPropertyInference.ts, 21, 7)) >parseInt : Symbol(parseInt, Decl(lib.es5.d.ts, --, --)) ->s : Symbol(s, Decl(discriminantPropertyInference.ts, 19, 7)) +>s : Symbol(s, Decl(discriminantPropertyInference.ts, 21, 7)) }); // simple inference f({ ->f : Symbol(f, Decl(discriminantPropertyInference.ts, 12, 52)) +>f : Symbol(f, Decl(discriminantPropertyInference.ts, 14, 1)) disc: false, ->disc : Symbol(disc, Decl(discriminantPropertyInference.ts, 23, 3)) +>disc : Symbol(disc, Decl(discriminantPropertyInference.ts, 25, 3)) cb: n => n.toFixed() ->cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 24, 16)) ->n : Symbol(n, Decl(discriminantPropertyInference.ts, 25, 7)) +>cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 26, 16)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 27, 7)) >n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) ->n : Symbol(n, Decl(discriminantPropertyInference.ts, 25, 7)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 27, 7)) >toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) }); // simple inference when strict-null-checks are enabled f({ ->f : Symbol(f, Decl(discriminantPropertyInference.ts, 12, 52)) +>f : Symbol(f, Decl(discriminantPropertyInference.ts, 14, 1)) disc: undefined, ->disc : Symbol(disc, Decl(discriminantPropertyInference.ts, 29, 3)) +>disc : Symbol(disc, Decl(discriminantPropertyInference.ts, 31, 3)) >undefined : Symbol(undefined) cb: n => n.toFixed() ->cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 30, 20)) ->n : Symbol(n, Decl(discriminantPropertyInference.ts, 31, 7)) +>cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 32, 20)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 33, 7)) >n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) ->n : Symbol(n, Decl(discriminantPropertyInference.ts, 31, 7)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 33, 7)) >toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) }); // requires checking type information since discriminator is missing from object f({ ->f : Symbol(f, Decl(discriminantPropertyInference.ts, 12, 52)) +>f : Symbol(f, Decl(discriminantPropertyInference.ts, 14, 1)) + + cb: n => n.toFixed() +>cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 37, 3)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 38, 7)) +>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 38, 7)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +}); + + +declare function g(options: DiscriminatorTrue | DiscriminatorFalse | Unrelated): any; +>g : Symbol(g, Decl(discriminantPropertyInference.ts, 39, 3)) +>options : Symbol(options, Decl(discriminantPropertyInference.ts, 42, 19)) +>DiscriminatorTrue : Symbol(DiscriminatorTrue, Decl(discriminantPropertyInference.ts, 0, 0)) +>DiscriminatorFalse : Symbol(DiscriminatorFalse, Decl(discriminantPropertyInference.ts, 5, 1)) +>Unrelated : Symbol(Unrelated, Decl(discriminantPropertyInference.ts, 10, 1)) + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +g({ +>g : Symbol(g, Decl(discriminantPropertyInference.ts, 39, 3)) cb: n => n.toFixed() ->cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 35, 3)) ->n : Symbol(n, Decl(discriminantPropertyInference.ts, 36, 7)) +>cb : Symbol(cb, Decl(discriminantPropertyInference.ts, 45, 3)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 46, 7)) >n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) ->n : Symbol(n, Decl(discriminantPropertyInference.ts, 36, 7)) +>n : Symbol(n, Decl(discriminantPropertyInference.ts, 46, 7)) >toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) }); diff --git a/tests/baselines/reference/discriminantPropertyInference.types b/tests/baselines/reference/discriminantPropertyInference.types index 2ebc6c6a373fe..eef51e40a173f 100644 --- a/tests/baselines/reference/discriminantPropertyInference.types +++ b/tests/baselines/reference/discriminantPropertyInference.types @@ -25,8 +25,12 @@ type DiscriminatorFalse = { >x : number } -type Props = DiscriminatorTrue | DiscriminatorFalse; ->Props : Props +type Unrelated = { +>Unrelated : Unrelated + + val: number; +>val : number +} declare function f(options: DiscriminatorTrue | DiscriminatorFalse): any; >f : (options: DiscriminatorTrue | DiscriminatorFalse) => any @@ -111,3 +115,25 @@ f({ }); + +declare function g(options: DiscriminatorTrue | DiscriminatorFalse | Unrelated): any; +>g : (options: DiscriminatorTrue | DiscriminatorFalse | Unrelated) => any +>options : DiscriminatorTrue | DiscriminatorFalse | Unrelated + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +g({ +>g({ cb: n => n.toFixed()}) : any +>g : (options: DiscriminatorTrue | DiscriminatorFalse | Unrelated) => any +>{ cb: n => n.toFixed()} : { cb: (n: number) => string; } + + cb: n => n.toFixed() +>cb : (n: number) => string +>n => n.toFixed() : (n: number) => string +>n : number +>n.toFixed() : string +>n.toFixed : (fractionDigits?: number | undefined) => string +>n : number +>toFixed : (fractionDigits?: number | undefined) => string + +}); + diff --git a/tests/baselines/reference/tsxDiscriminantPropertyInference.js b/tests/baselines/reference/tsxDiscriminantPropertyInference.js index b374f4690b0a4..39da73242f056 100644 --- a/tests/baselines/reference/tsxDiscriminantPropertyInference.js +++ b/tests/baselines/reference/tsxDiscriminantPropertyInference.js @@ -14,9 +14,15 @@ type DiscriminatorFalse = { cb: (x: number) => void; } +type Unrelated = { + val: number; +} + type Props = DiscriminatorTrue | DiscriminatorFalse; -declare function Comp(props: DiscriminatorTrue | DiscriminatorFalse): JSX.Element; +type UnrelatedProps = Props | Unrelated; + +declare function Comp(props: Props): JSX.Element; // simple inference void ( parseInt(s)} />); @@ -29,6 +35,11 @@ void ( n.toFixed()} />); // requires checking type information since discriminator is missing from object void ( n.toFixed()} />); + +declare function UnrelatedComp(props: UnrelatedProps): JSX.Element; + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +void ( n.toFixed()} />); //// [tsxDiscriminantPropertyInference.jsx] @@ -40,3 +51,5 @@ void (); void (); // requires checking type information since discriminator is missing from object void (); +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +void (); diff --git a/tests/baselines/reference/tsxDiscriminantPropertyInference.symbols b/tests/baselines/reference/tsxDiscriminantPropertyInference.symbols index 4b74166e91b63..d7a1f94ae719f 100644 --- a/tests/baselines/reference/tsxDiscriminantPropertyInference.symbols +++ b/tests/baselines/reference/tsxDiscriminantPropertyInference.symbols @@ -29,55 +29,82 @@ type DiscriminatorFalse = { >x : Symbol(x, Decl(tsxDiscriminantPropertyInference.tsx, 12, 9)) } +type Unrelated = { +>Unrelated : Symbol(Unrelated, Decl(tsxDiscriminantPropertyInference.tsx, 13, 1)) + + val: number; +>val : Symbol(val, Decl(tsxDiscriminantPropertyInference.tsx, 15, 18)) +} + type Props = DiscriminatorTrue | DiscriminatorFalse; ->Props : Symbol(Props, Decl(tsxDiscriminantPropertyInference.tsx, 13, 1)) +>Props : Symbol(Props, Decl(tsxDiscriminantPropertyInference.tsx, 17, 1)) >DiscriminatorTrue : Symbol(DiscriminatorTrue, Decl(tsxDiscriminantPropertyInference.tsx, 3, 1)) >DiscriminatorFalse : Symbol(DiscriminatorFalse, Decl(tsxDiscriminantPropertyInference.tsx, 8, 1)) -declare function Comp(props: DiscriminatorTrue | DiscriminatorFalse): JSX.Element; ->Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 15, 52)) ->props : Symbol(props, Decl(tsxDiscriminantPropertyInference.tsx, 17, 22)) ->DiscriminatorTrue : Symbol(DiscriminatorTrue, Decl(tsxDiscriminantPropertyInference.tsx, 3, 1)) ->DiscriminatorFalse : Symbol(DiscriminatorFalse, Decl(tsxDiscriminantPropertyInference.tsx, 8, 1)) +type UnrelatedProps = Props | Unrelated; +>UnrelatedProps : Symbol(UnrelatedProps, Decl(tsxDiscriminantPropertyInference.tsx, 19, 52)) +>Props : Symbol(Props, Decl(tsxDiscriminantPropertyInference.tsx, 17, 1)) +>Unrelated : Symbol(Unrelated, Decl(tsxDiscriminantPropertyInference.tsx, 13, 1)) + +declare function Comp(props: Props): JSX.Element; +>Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 21, 40)) +>props : Symbol(props, Decl(tsxDiscriminantPropertyInference.tsx, 23, 22)) +>Props : Symbol(Props, Decl(tsxDiscriminantPropertyInference.tsx, 17, 1)) >JSX : Symbol(JSX, Decl(tsxDiscriminantPropertyInference.tsx, 0, 0)) >Element : Symbol(JSX.Element, Decl(tsxDiscriminantPropertyInference.tsx, 1, 15)) // simple inference void ( parseInt(s)} />); ->Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 15, 52)) ->disc : Symbol(disc, Decl(tsxDiscriminantPropertyInference.tsx, 20, 11)) ->cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 20, 16)) ->s : Symbol(s, Decl(tsxDiscriminantPropertyInference.tsx, 20, 21)) +>Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 21, 40)) +>disc : Symbol(disc, Decl(tsxDiscriminantPropertyInference.tsx, 26, 11)) +>cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 26, 16)) +>s : Symbol(s, Decl(tsxDiscriminantPropertyInference.tsx, 26, 21)) >parseInt : Symbol(parseInt, Decl(lib.es5.d.ts, --, --)) ->s : Symbol(s, Decl(tsxDiscriminantPropertyInference.tsx, 20, 21)) +>s : Symbol(s, Decl(tsxDiscriminantPropertyInference.tsx, 26, 21)) // simple inference void ( n.toFixed()} />); ->Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 15, 52)) ->disc : Symbol(disc, Decl(tsxDiscriminantPropertyInference.tsx, 23, 11)) ->cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 23, 24)) ->n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 23, 29)) +>Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 21, 40)) +>disc : Symbol(disc, Decl(tsxDiscriminantPropertyInference.tsx, 29, 11)) +>cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 29, 24)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 29, 29)) >n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) ->n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 23, 29)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 29, 29)) >toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) // simple inference when strict-null-checks are enabled void ( n.toFixed()} />); ->Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 15, 52)) ->disc : Symbol(disc, Decl(tsxDiscriminantPropertyInference.tsx, 26, 11)) +>Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 21, 40)) +>disc : Symbol(disc, Decl(tsxDiscriminantPropertyInference.tsx, 32, 11)) >undefined : Symbol(undefined) ->cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 26, 28)) ->n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 26, 33)) +>cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 32, 28)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 32, 33)) >n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) ->n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 26, 33)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 32, 33)) >toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) // requires checking type information since discriminator is missing from object void ( n.toFixed()} />); ->Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 15, 52)) ->cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 29, 11)) ->n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 29, 16)) +>Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 21, 40)) +>cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 35, 11)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 35, 16)) +>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 35, 16)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +declare function UnrelatedComp(props: UnrelatedProps): JSX.Element; +>UnrelatedComp : Symbol(UnrelatedComp, Decl(tsxDiscriminantPropertyInference.tsx, 35, 38)) +>props : Symbol(props, Decl(tsxDiscriminantPropertyInference.tsx, 37, 31)) +>UnrelatedProps : Symbol(UnrelatedProps, Decl(tsxDiscriminantPropertyInference.tsx, 19, 52)) +>JSX : Symbol(JSX, Decl(tsxDiscriminantPropertyInference.tsx, 0, 0)) +>Element : Symbol(JSX.Element, Decl(tsxDiscriminantPropertyInference.tsx, 1, 15)) + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +void ( n.toFixed()} />); +>Comp : Symbol(Comp, Decl(tsxDiscriminantPropertyInference.tsx, 21, 40)) +>cb : Symbol(cb, Decl(tsxDiscriminantPropertyInference.tsx, 40, 11)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 40, 16)) >n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) ->n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 29, 16)) +>n : Symbol(n, Decl(tsxDiscriminantPropertyInference.tsx, 40, 16)) >toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) diff --git a/tests/baselines/reference/tsxDiscriminantPropertyInference.types b/tests/baselines/reference/tsxDiscriminantPropertyInference.types index 63932bd18d963..49a89d29ef7ce 100644 --- a/tests/baselines/reference/tsxDiscriminantPropertyInference.types +++ b/tests/baselines/reference/tsxDiscriminantPropertyInference.types @@ -28,12 +28,22 @@ type DiscriminatorFalse = { >x : number } +type Unrelated = { +>Unrelated : Unrelated + + val: number; +>val : number +} + type Props = DiscriminatorTrue | DiscriminatorFalse; >Props : Props -declare function Comp(props: DiscriminatorTrue | DiscriminatorFalse): JSX.Element; ->Comp : (props: DiscriminatorTrue | DiscriminatorFalse) => JSX.Element ->props : DiscriminatorTrue | DiscriminatorFalse +type UnrelatedProps = Props | Unrelated; +>UnrelatedProps : UnrelatedProps + +declare function Comp(props: Props): JSX.Element; +>Comp : (props: Props) => JSX.Element +>props : Props >JSX : any // simple inference @@ -41,7 +51,7 @@ void ( parseInt(s)} />); >void ( parseInt(s)} />) : undefined >( parseInt(s)} />) : JSX.Element > parseInt(s)} /> : JSX.Element ->Comp : (props: DiscriminatorTrue | DiscriminatorFalse) => JSX.Element +>Comp : (props: Props) => JSX.Element >disc : true >cb : (s: string) => number >s => parseInt(s) : (s: string) => number @@ -55,7 +65,7 @@ void ( n.toFixed()} />); >void ( n.toFixed()} />) : undefined >( n.toFixed()} />) : JSX.Element > n.toFixed()} /> : JSX.Element ->Comp : (props: DiscriminatorTrue | DiscriminatorFalse) => JSX.Element +>Comp : (props: Props) => JSX.Element >disc : false >false : false >cb : (n: number) => string @@ -71,7 +81,7 @@ void ( n.toFixed()} />); >void ( n.toFixed()} />) : undefined >( n.toFixed()} />) : JSX.Element > n.toFixed()} /> : JSX.Element ->Comp : (props: DiscriminatorTrue | DiscriminatorFalse) => JSX.Element +>Comp : (props: Props) => JSX.Element >disc : undefined >undefined : undefined >cb : (n: number) => string @@ -87,7 +97,26 @@ void ( n.toFixed()} />); >void ( n.toFixed()} />) : undefined >( n.toFixed()} />) : JSX.Element > n.toFixed()} /> : JSX.Element ->Comp : (props: DiscriminatorTrue | DiscriminatorFalse) => JSX.Element +>Comp : (props: Props) => JSX.Element +>cb : (n: number) => string +>n => n.toFixed() : (n: number) => string +>n : number +>n.toFixed() : string +>n.toFixed : (fractionDigits?: number | undefined) => string +>n : number +>toFixed : (fractionDigits?: number | undefined) => string + +declare function UnrelatedComp(props: UnrelatedProps): JSX.Element; +>UnrelatedComp : (props: UnrelatedProps) => JSX.Element +>props : UnrelatedProps +>JSX : any + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +void ( n.toFixed()} />); +>void ( n.toFixed()} />) : undefined +>( n.toFixed()} />) : JSX.Element +> n.toFixed()} /> : JSX.Element +>Comp : (props: Props) => JSX.Element >cb : (n: number) => string >n => n.toFixed() : (n: number) => string >n : number diff --git a/tests/cases/compiler/discriminantPropertyInference.ts b/tests/cases/compiler/discriminantPropertyInference.ts index 5aeb0dd0c0d7a..e2b39488b218d 100644 --- a/tests/cases/compiler/discriminantPropertyInference.ts +++ b/tests/cases/compiler/discriminantPropertyInference.ts @@ -13,7 +13,9 @@ type DiscriminatorFalse = { cb: (x: number) => void; } -type Props = DiscriminatorTrue | DiscriminatorFalse; +type Unrelated = { + val: number; +} declare function f(options: DiscriminatorTrue | DiscriminatorFalse): any; @@ -39,3 +41,11 @@ f({ f({ cb: n => n.toFixed() }); + + +declare function g(options: DiscriminatorTrue | DiscriminatorFalse | Unrelated): any; + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +g({ + cb: n => n.toFixed() +}); diff --git a/tests/cases/compiler/tsxDiscriminantPropertyInference.tsx b/tests/cases/compiler/tsxDiscriminantPropertyInference.tsx index d4db0f82d50a0..d4fe3baf37851 100644 --- a/tests/cases/compiler/tsxDiscriminantPropertyInference.tsx +++ b/tests/cases/compiler/tsxDiscriminantPropertyInference.tsx @@ -17,9 +17,15 @@ type DiscriminatorFalse = { cb: (x: number) => void; } +type Unrelated = { + val: number; +} + type Props = DiscriminatorTrue | DiscriminatorFalse; -declare function Comp(props: DiscriminatorTrue | DiscriminatorFalse): JSX.Element; +type UnrelatedProps = Props | Unrelated; + +declare function Comp(props: Props): JSX.Element; // simple inference void ( parseInt(s)} />); @@ -32,3 +38,8 @@ void ( n.toFixed()} />); // requires checking type information since discriminator is missing from object void ( n.toFixed()} />); + +declare function UnrelatedComp(props: UnrelatedProps): JSX.Element; + +// requires checking properties of all types, rather than properties of just the union type (e.g. only intersection) +void ( n.toFixed()} />);