Improve indexed access inferences (#27015)
This commit is contained in:
parent
bc709a87ad
commit
c3b4f72498
|
@ -13373,7 +13373,7 @@ namespace ts {
|
|||
let propagationType: Type;
|
||||
inferFromTypes(originalSource, originalTarget);
|
||||
|
||||
function inferFromTypes(source: Type, target: Type) {
|
||||
function inferFromTypes(source: Type, target: Type): void {
|
||||
if (!couldContainTypeVariables(target)) {
|
||||
return;
|
||||
}
|
||||
|
@ -13541,7 +13541,14 @@ namespace ts {
|
|||
}
|
||||
else {
|
||||
if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) {
|
||||
source = getApparentType(source);
|
||||
const apparentSource = getApparentType(source);
|
||||
// getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type.
|
||||
// If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes`
|
||||
// with the simplified source.
|
||||
if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
|
||||
return inferFromTypes(apparentSource, target);
|
||||
}
|
||||
source = apparentSource;
|
||||
}
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
||||
const key = source.id + "," + target.id;
|
||||
|
|
45
tests/baselines/reference/voidReturnIndexUnionInference.js
Normal file
45
tests/baselines/reference/voidReturnIndexUnionInference.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
//// [voidReturnIndexUnionInference.ts]
|
||||
// repro from https://github.com/Microsoft/TypeScript/issues/25274
|
||||
export function safeInvoke<A1, R>(
|
||||
func: ((arg1: A1) => R) | null | undefined,
|
||||
arg1: A1
|
||||
): R | undefined {
|
||||
if (func) {
|
||||
return func(arg1);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onFoo?(value: string): boolean;
|
||||
onBar?(value: string): void;
|
||||
}
|
||||
|
||||
function bad<P extends Props>(props: Readonly<P>) {
|
||||
safeInvoke(props.onFoo, "blah");
|
||||
// ERROR HERE!!!
|
||||
// Type R in signature of safeInvoke incorrectly inferred as {} instead of void!
|
||||
safeInvoke(props.onBar, "blah");
|
||||
}
|
||||
|
||||
|
||||
//// [voidReturnIndexUnionInference.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
// repro from https://github.com/Microsoft/TypeScript/issues/25274
|
||||
function safeInvoke(func, arg1) {
|
||||
if (func) {
|
||||
return func(arg1);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
exports.safeInvoke = safeInvoke;
|
||||
function bad(props) {
|
||||
safeInvoke(props.onFoo, "blah");
|
||||
// ERROR HERE!!!
|
||||
// Type R in signature of safeInvoke incorrectly inferred as {} instead of void!
|
||||
safeInvoke(props.onBar, "blah");
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
=== tests/cases/compiler/voidReturnIndexUnionInference.ts ===
|
||||
// repro from https://github.com/Microsoft/TypeScript/issues/25274
|
||||
export function safeInvoke<A1, R>(
|
||||
>safeInvoke : Symbol(safeInvoke, Decl(voidReturnIndexUnionInference.ts, 0, 0))
|
||||
>A1 : Symbol(A1, Decl(voidReturnIndexUnionInference.ts, 1, 27))
|
||||
>R : Symbol(R, Decl(voidReturnIndexUnionInference.ts, 1, 30))
|
||||
|
||||
func: ((arg1: A1) => R) | null | undefined,
|
||||
>func : Symbol(func, Decl(voidReturnIndexUnionInference.ts, 1, 34))
|
||||
>arg1 : Symbol(arg1, Decl(voidReturnIndexUnionInference.ts, 2, 12))
|
||||
>A1 : Symbol(A1, Decl(voidReturnIndexUnionInference.ts, 1, 27))
|
||||
>R : Symbol(R, Decl(voidReturnIndexUnionInference.ts, 1, 30))
|
||||
|
||||
arg1: A1
|
||||
>arg1 : Symbol(arg1, Decl(voidReturnIndexUnionInference.ts, 2, 47))
|
||||
>A1 : Symbol(A1, Decl(voidReturnIndexUnionInference.ts, 1, 27))
|
||||
|
||||
): R | undefined {
|
||||
>R : Symbol(R, Decl(voidReturnIndexUnionInference.ts, 1, 30))
|
||||
|
||||
if (func) {
|
||||
>func : Symbol(func, Decl(voidReturnIndexUnionInference.ts, 1, 34))
|
||||
|
||||
return func(arg1);
|
||||
>func : Symbol(func, Decl(voidReturnIndexUnionInference.ts, 1, 34))
|
||||
>arg1 : Symbol(arg1, Decl(voidReturnIndexUnionInference.ts, 2, 47))
|
||||
|
||||
} else {
|
||||
return undefined;
|
||||
>undefined : Symbol(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
>Props : Symbol(Props, Decl(voidReturnIndexUnionInference.ts, 10, 1))
|
||||
|
||||
onFoo?(value: string): boolean;
|
||||
>onFoo : Symbol(Props.onFoo, Decl(voidReturnIndexUnionInference.ts, 12, 17))
|
||||
>value : Symbol(value, Decl(voidReturnIndexUnionInference.ts, 13, 11))
|
||||
|
||||
onBar?(value: string): void;
|
||||
>onBar : Symbol(Props.onBar, Decl(voidReturnIndexUnionInference.ts, 13, 35))
|
||||
>value : Symbol(value, Decl(voidReturnIndexUnionInference.ts, 14, 11))
|
||||
}
|
||||
|
||||
function bad<P extends Props>(props: Readonly<P>) {
|
||||
>bad : Symbol(bad, Decl(voidReturnIndexUnionInference.ts, 15, 1))
|
||||
>P : Symbol(P, Decl(voidReturnIndexUnionInference.ts, 17, 13))
|
||||
>Props : Symbol(Props, Decl(voidReturnIndexUnionInference.ts, 10, 1))
|
||||
>props : Symbol(props, Decl(voidReturnIndexUnionInference.ts, 17, 30))
|
||||
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(voidReturnIndexUnionInference.ts, 17, 13))
|
||||
|
||||
safeInvoke(props.onFoo, "blah");
|
||||
>safeInvoke : Symbol(safeInvoke, Decl(voidReturnIndexUnionInference.ts, 0, 0))
|
||||
>props.onFoo : Symbol(onFoo, Decl(voidReturnIndexUnionInference.ts, 12, 17))
|
||||
>props : Symbol(props, Decl(voidReturnIndexUnionInference.ts, 17, 30))
|
||||
>onFoo : Symbol(onFoo, Decl(voidReturnIndexUnionInference.ts, 12, 17))
|
||||
|
||||
// ERROR HERE!!!
|
||||
// Type R in signature of safeInvoke incorrectly inferred as {} instead of void!
|
||||
safeInvoke(props.onBar, "blah");
|
||||
>safeInvoke : Symbol(safeInvoke, Decl(voidReturnIndexUnionInference.ts, 0, 0))
|
||||
>props.onBar : Symbol(onBar, Decl(voidReturnIndexUnionInference.ts, 13, 35))
|
||||
>props : Symbol(props, Decl(voidReturnIndexUnionInference.ts, 17, 30))
|
||||
>onBar : Symbol(onBar, Decl(voidReturnIndexUnionInference.ts, 13, 35))
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
=== tests/cases/compiler/voidReturnIndexUnionInference.ts ===
|
||||
// repro from https://github.com/Microsoft/TypeScript/issues/25274
|
||||
export function safeInvoke<A1, R>(
|
||||
>safeInvoke : <A1, R>(func: ((arg1: A1) => R) | null | undefined, arg1: A1) => R | undefined
|
||||
|
||||
func: ((arg1: A1) => R) | null | undefined,
|
||||
>func : ((arg1: A1) => R) | null | undefined
|
||||
>arg1 : A1
|
||||
>null : null
|
||||
|
||||
arg1: A1
|
||||
>arg1 : A1
|
||||
|
||||
): R | undefined {
|
||||
if (func) {
|
||||
>func : ((arg1: A1) => R) | null | undefined
|
||||
|
||||
return func(arg1);
|
||||
>func(arg1) : R
|
||||
>func : (arg1: A1) => R
|
||||
>arg1 : A1
|
||||
|
||||
} else {
|
||||
return undefined;
|
||||
>undefined : undefined
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onFoo?(value: string): boolean;
|
||||
>onFoo : ((value: string) => boolean) | undefined
|
||||
>value : string
|
||||
|
||||
onBar?(value: string): void;
|
||||
>onBar : ((value: string) => void) | undefined
|
||||
>value : string
|
||||
}
|
||||
|
||||
function bad<P extends Props>(props: Readonly<P>) {
|
||||
>bad : <P extends Props>(props: Readonly<P>) => void
|
||||
>props : Readonly<P>
|
||||
|
||||
safeInvoke(props.onFoo, "blah");
|
||||
>safeInvoke(props.onFoo, "blah") : boolean | undefined
|
||||
>safeInvoke : <A1, R>(func: ((arg1: A1) => R) | null | undefined, arg1: A1) => R | undefined
|
||||
>props.onFoo : P["onFoo"]
|
||||
>props : Readonly<P>
|
||||
>onFoo : P["onFoo"]
|
||||
>"blah" : "blah"
|
||||
|
||||
// ERROR HERE!!!
|
||||
// Type R in signature of safeInvoke incorrectly inferred as {} instead of void!
|
||||
safeInvoke(props.onBar, "blah");
|
||||
>safeInvoke(props.onBar, "blah") : void | undefined
|
||||
>safeInvoke : <A1, R>(func: ((arg1: A1) => R) | null | undefined, arg1: A1) => R | undefined
|
||||
>props.onBar : P["onBar"]
|
||||
>props : Readonly<P>
|
||||
>onBar : P["onBar"]
|
||||
>"blah" : "blah"
|
||||
}
|
||||
|
24
tests/cases/compiler/voidReturnIndexUnionInference.ts
Normal file
24
tests/cases/compiler/voidReturnIndexUnionInference.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
// @strict: true
|
||||
// repro from https://github.com/Microsoft/TypeScript/issues/25274
|
||||
export function safeInvoke<A1, R>(
|
||||
func: ((arg1: A1) => R) | null | undefined,
|
||||
arg1: A1
|
||||
): R | undefined {
|
||||
if (func) {
|
||||
return func(arg1);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onFoo?(value: string): boolean;
|
||||
onBar?(value: string): void;
|
||||
}
|
||||
|
||||
function bad<P extends Props>(props: Readonly<P>) {
|
||||
safeInvoke(props.onFoo, "blah");
|
||||
// ERROR HERE!!!
|
||||
// Type R in signature of safeInvoke incorrectly inferred as {} instead of void!
|
||||
safeInvoke(props.onBar, "blah");
|
||||
}
|
Loading…
Reference in a new issue