From b9936e3548d1072eacaf573cafb484127db77e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 18 Jun 2024 09:50:20 +0200 Subject: [PATCH 1/7] Filter return type inferences by constraint applicability --- src/compiler/checker.ts | 23 +++++- ...nferenceContextualReturnTypeUnion1.symbols | 53 ++++++++++++ .../inferenceContextualReturnTypeUnion1.types | 82 +++++++++++++++++++ .../inferenceContextualReturnTypeUnion1.ts | 19 +++++ 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion1.symbols create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion1.types create mode 100644 tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3e64493503c42..e4fcdb3f13116 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26848,14 +26848,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constraint = getConstraintOfTypeParameter(inference.typeParameter); if (constraint) { const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper); - if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { - // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint. - inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; + if (!inferredType) { + inference.inferredType = instantiatedConstraint; + } + else { + if (inference.priority! & InferencePriority.ReturnType) { + inference.inferredType = filterContextualInferredType(inferredType, instantiatedConstraint) ?? (fallbackType && filterContextualInferredType(fallbackType, instantiatedConstraint)) ?? instantiatedConstraint; + } + else if (!context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { + // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint. + inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; + } } } } return inference.inferredType; + + function filterContextualInferredType(inferredType: Type, constraint: Type) { + if (inferredType.flags & TypeFlags.Never) { + return inferredType; + } + const constraintWithThisArgument = getTypeWithThisArgument(constraint, inferredType); + const applicableByConstraint = filterType(inferredType, t => !!context.compareTypes(t, constraintWithThisArgument)); + return !(applicableByConstraint.flags & TypeFlags.Never) ? inferredType : undefined; + } } function getDefaultTypeArgumentType(isInJavaScriptFile: boolean): Type { diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion1.symbols b/tests/baselines/reference/inferenceContextualReturnTypeUnion1.symbols new file mode 100644 index 0000000000000..6d1ffd4d47c96 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion1.symbols @@ -0,0 +1,53 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts] //// + +=== inferenceContextualReturnTypeUnion1.ts === +// https://github.com/microsoft/TypeScript/issues/50719 + +declare function useCallback1(fn: T): T; +>useCallback1 : Symbol(useCallback1, Decl(inferenceContextualReturnTypeUnion1.ts, 0, 0)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion1.ts, 2, 30)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>fn : Symbol(fn, Decl(inferenceContextualReturnTypeUnion1.ts, 2, 50)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion1.ts, 2, 30)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion1.ts, 2, 30)) + +declare function ex2(callback?: (x: number) => void): void; +>ex2 : Symbol(ex2, Decl(inferenceContextualReturnTypeUnion1.ts, 2, 60)) +>callback : Symbol(callback, Decl(inferenceContextualReturnTypeUnion1.ts, 4, 21)) +>x : Symbol(x, Decl(inferenceContextualReturnTypeUnion1.ts, 4, 33)) + +ex2(useCallback1((x) => {})); +>ex2 : Symbol(ex2, Decl(inferenceContextualReturnTypeUnion1.ts, 2, 60)) +>useCallback1 : Symbol(useCallback1, Decl(inferenceContextualReturnTypeUnion1.ts, 0, 0)) +>x : Symbol(x, Decl(inferenceContextualReturnTypeUnion1.ts, 5, 18)) + +declare function ex3(callback: ((x: number) => void) | 5): void; +>ex3 : Symbol(ex3, Decl(inferenceContextualReturnTypeUnion1.ts, 5, 29)) +>callback : Symbol(callback, Decl(inferenceContextualReturnTypeUnion1.ts, 7, 21)) +>x : Symbol(x, Decl(inferenceContextualReturnTypeUnion1.ts, 7, 33)) + +ex3(useCallback1((x) => {})); +>ex3 : Symbol(ex3, Decl(inferenceContextualReturnTypeUnion1.ts, 5, 29)) +>useCallback1 : Symbol(useCallback1, Decl(inferenceContextualReturnTypeUnion1.ts, 0, 0)) +>x : Symbol(x, Decl(inferenceContextualReturnTypeUnion1.ts, 8, 18)) + +// https://github.com/microsoft/TypeScript/issues/41461 + +declare function useCallback2 any>( +>useCallback2 : Symbol(useCallback2, Decl(inferenceContextualReturnTypeUnion1.ts, 8, 29)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion1.ts, 12, 30)) +>args : Symbol(args, Decl(inferenceContextualReturnTypeUnion1.ts, 12, 41)) + + callback: T, +>callback : Symbol(callback, Decl(inferenceContextualReturnTypeUnion1.ts, 12, 65)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion1.ts, 12, 30)) + +): T; +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion1.ts, 12, 30)) + +const test: ((x: string) => void) | undefined = useCallback2((x) => {}); +>test : Symbol(test, Decl(inferenceContextualReturnTypeUnion1.ts, 15, 5)) +>x : Symbol(x, Decl(inferenceContextualReturnTypeUnion1.ts, 15, 14)) +>useCallback2 : Symbol(useCallback2, Decl(inferenceContextualReturnTypeUnion1.ts, 8, 29)) +>x : Symbol(x, Decl(inferenceContextualReturnTypeUnion1.ts, 15, 62)) + diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion1.types b/tests/baselines/reference/inferenceContextualReturnTypeUnion1.types new file mode 100644 index 0000000000000..fd85d18736427 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion1.types @@ -0,0 +1,82 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts] //// + +=== inferenceContextualReturnTypeUnion1.ts === +// https://github.com/microsoft/TypeScript/issues/50719 + +declare function useCallback1(fn: T): T; +>useCallback1 : (fn: T) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>fn : T +> : ^ + +declare function ex2(callback?: (x: number) => void): void; +>ex2 : (callback?: (x: number) => void) => void +> : ^ ^^^ ^^^^^ +>callback : ((x: number) => void) | undefined +> : ^^ ^^ ^^^^^ ^^^^^^^^^^^^^ +>x : number +> : ^^^^^^ + +ex2(useCallback1((x) => {})); +>ex2(useCallback1((x) => {})) : void +> : ^^^^ +>ex2 : (callback?: (x: number) => void) => void +> : ^ ^^^ ^^^^^ +>useCallback1((x) => {}) : (x: number) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>useCallback1 : (fn: T) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>(x) => {} : (x: number) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>x : number +> : ^^^^^^ + +declare function ex3(callback: ((x: number) => void) | 5): void; +>ex3 : (callback: ((x: number) => void) | 5) => void +> : ^ ^^ ^^^^^ +>callback : ((x: number) => void) | 5 +> : ^^ ^^ ^^^^^ ^^^^^ +>x : number +> : ^^^^^^ + +ex3(useCallback1((x) => {})); +>ex3(useCallback1((x) => {})) : void +> : ^^^^ +>ex3 : (callback: ((x: number) => void) | 5) => void +> : ^ ^^ ^^^^^ +>useCallback1((x) => {}) : (x: number) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>useCallback1 : (fn: T) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>(x) => {} : (x: number) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>x : number +> : ^^^^^^ + +// https://github.com/microsoft/TypeScript/issues/41461 + +declare function useCallback2 any>( +>useCallback2 : any>(callback: T) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>args : any[] +> : ^^^^^ + + callback: T, +>callback : T +> : ^ + +): T; +const test: ((x: string) => void) | undefined = useCallback2((x) => {}); +>test : ((x: string) => void) | undefined +> : ^^ ^^ ^^^^^ ^^^^^^^^^^^^^ +>x : string +> : ^^^^^^ +>useCallback2((x) => {}) : (x: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>useCallback2 : any>(callback: T) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>(x) => {} : (x: string) => void +> : ^ ^^^^^^^^^^^^^^^^^ +>x : string +> : ^^^^^^ + diff --git a/tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts b/tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts new file mode 100644 index 0000000000000..ab3963fd9d62a --- /dev/null +++ b/tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts @@ -0,0 +1,19 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/50719 + +declare function useCallback1(fn: T): T; + +declare function ex2(callback?: (x: number) => void): void; +ex2(useCallback1((x) => {})); + +declare function ex3(callback: ((x: number) => void) | 5): void; +ex3(useCallback1((x) => {})); + +// https://github.com/microsoft/TypeScript/issues/41461 + +declare function useCallback2 any>( + callback: T, +): T; +const test: ((x: string) => void) | undefined = useCallback2((x) => {}); From 0ecedb648125fd203948f00b8ea6f31ed688fadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 13 Jul 2024 19:07:03 +0200 Subject: [PATCH 2/7] fixed a silly mistake --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fd62aa203c86a..2316677e692ad 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26916,7 +26916,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const constraintWithThisArgument = getTypeWithThisArgument(constraint, inferredType); const applicableByConstraint = filterType(inferredType, t => !!context.compareTypes(t, constraintWithThisArgument)); - return !(applicableByConstraint.flags & TypeFlags.Never) ? inferredType : undefined; + return !(applicableByConstraint.flags & TypeFlags.Never) ? applicableByConstraint : undefined; } } From b7418c7c333e6be4e7c60be2b6813443f77436af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 13 Jul 2024 19:34:09 +0200 Subject: [PATCH 3/7] add extra test case --- ...nferenceContextualReturnTypeUnion2.symbols | 97 +++++++++++++++++++ .../inferenceContextualReturnTypeUnion2.types | 74 ++++++++++++++ .../inferenceContextualReturnTypeUnion2.ts | 35 +++++++ 3 files changed, 206 insertions(+) create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion2.symbols create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion2.types create mode 100644 tests/cases/compiler/inferenceContextualReturnTypeUnion2.ts diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion2.symbols b/tests/baselines/reference/inferenceContextualReturnTypeUnion2.symbols new file mode 100644 index 0000000000000..d46672fb09211 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion2.symbols @@ -0,0 +1,97 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion2.ts] //// + +=== inferenceContextualReturnTypeUnion2.ts === +type Query = ( +>Query : Symbol(Query, Decl(inferenceContextualReturnTypeUnion2.ts, 0, 0)) + + container: HTMLElement, +>container : Symbol(container, Decl(inferenceContextualReturnTypeUnion2.ts, 0, 14)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + ...args: any[] +>args : Symbol(args, Decl(inferenceContextualReturnTypeUnion2.ts, 1, 25)) + +) => + | Error +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --)) + + | HTMLElement +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + | HTMLElement[] +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + | Promise +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + | Promise +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + | null; + +interface Queries { +>Queries : Symbol(Queries, Decl(inferenceContextualReturnTypeUnion2.ts, 9, 9)) + + [T: string]: Query; +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion2.ts, 12, 3)) +>Query : Symbol(Query, Decl(inferenceContextualReturnTypeUnion2.ts, 0, 0)) +} + +type FindByText = ( +>FindByText : Symbol(FindByText, Decl(inferenceContextualReturnTypeUnion2.ts, 13, 1)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion2.ts, 15, 16)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + container: HTMLElement, +>container : Symbol(container, Decl(inferenceContextualReturnTypeUnion2.ts, 15, 56)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + text: string, +>text : Symbol(text, Decl(inferenceContextualReturnTypeUnion2.ts, 16, 25)) + +) => Promise; +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion2.ts, 15, 16)) + +declare function findByLabelText( +>findByLabelText : Symbol(findByLabelText, Decl(inferenceContextualReturnTypeUnion2.ts, 18, 16)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion2.ts, 20, 33)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + ...args: Parameters> +>args : Symbol(args, Decl(inferenceContextualReturnTypeUnion2.ts, 20, 70)) +>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --)) +>FindByText : Symbol(FindByText, Decl(inferenceContextualReturnTypeUnion2.ts, 13, 1)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion2.ts, 20, 33)) + +): ReturnType>; +>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --)) +>FindByText : Symbol(FindByText, Decl(inferenceContextualReturnTypeUnion2.ts, 13, 1)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion2.ts, 20, 33)) + +const queries = { +>queries : Symbol(queries, Decl(inferenceContextualReturnTypeUnion2.ts, 24, 5)) + + findByLabelText, +>findByLabelText : Symbol(findByLabelText, Decl(inferenceContextualReturnTypeUnion2.ts, 24, 17)) + +}; + +type MapQueries = { +>MapQueries : Symbol(MapQueries, Decl(inferenceContextualReturnTypeUnion2.ts, 26, 2)) +>Q : Symbol(Q, Decl(inferenceContextualReturnTypeUnion2.ts, 28, 16)) +>Queries : Symbol(Queries, Decl(inferenceContextualReturnTypeUnion2.ts, 9, 9)) +>queries : Symbol(queries, Decl(inferenceContextualReturnTypeUnion2.ts, 24, 5)) + + [P in keyof Q]: Q[P]; +>P : Symbol(P, Decl(inferenceContextualReturnTypeUnion2.ts, 29, 3)) +>Q : Symbol(Q, Decl(inferenceContextualReturnTypeUnion2.ts, 28, 16)) +>Q : Symbol(Q, Decl(inferenceContextualReturnTypeUnion2.ts, 28, 16)) +>P : Symbol(P, Decl(inferenceContextualReturnTypeUnion2.ts, 29, 3)) + +}; + diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion2.types b/tests/baselines/reference/inferenceContextualReturnTypeUnion2.types new file mode 100644 index 0000000000000..4464c94ddeae0 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion2.types @@ -0,0 +1,74 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion2.ts] //// + +=== inferenceContextualReturnTypeUnion2.ts === +type Query = ( +>Query : Query +> : ^^^^^ + + container: HTMLElement, +>container : HTMLElement +> : ^^^^^^^^^^^ + + ...args: any[] +>args : any[] +> : ^^^^^ + +) => + | Error + | HTMLElement + | HTMLElement[] + | Promise + | Promise + | null; + +interface Queries { + [T: string]: Query; +>T : string +> : ^^^^^^ +} + +type FindByText = ( +>FindByText : FindByText +> : ^^^^^^^^^^^^^ + + container: HTMLElement, +>container : HTMLElement +> : ^^^^^^^^^^^ + + text: string, +>text : string +> : ^^^^^^ + +) => Promise; + +declare function findByLabelText( +>findByLabelText : (container: HTMLElement, text: string) => ReturnType> +> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...args: Parameters> +>args : [container: HTMLElement, text: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +): ReturnType>; + +const queries = { +>queries : { findByLabelText: (container: HTMLElement, text: string) => ReturnType>; } +> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ +>{ findByLabelText,} : { findByLabelText: (container: HTMLElement, text: string) => ReturnType>; } +> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ + + findByLabelText, +>findByLabelText : (container: HTMLElement, text: string) => ReturnType> +> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +}; + +type MapQueries = { +>MapQueries : MapQueries +> : ^^^^^^^^^^^^^ +>queries : { findByLabelText: (container: HTMLElement, text: string) => ReturnType>; } +> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ + + [P in keyof Q]: Q[P]; +}; + diff --git a/tests/cases/compiler/inferenceContextualReturnTypeUnion2.ts b/tests/cases/compiler/inferenceContextualReturnTypeUnion2.ts new file mode 100644 index 0000000000000..020249134492d --- /dev/null +++ b/tests/cases/compiler/inferenceContextualReturnTypeUnion2.ts @@ -0,0 +1,35 @@ +// @strict: true +// @lib: esnext, dom +// @noEmit: true + +type Query = ( + container: HTMLElement, + ...args: any[] +) => + | Error + | HTMLElement + | HTMLElement[] + | Promise + | Promise + | null; + +interface Queries { + [T: string]: Query; +} + +type FindByText = ( + container: HTMLElement, + text: string, +) => Promise; + +declare function findByLabelText( + ...args: Parameters> +): ReturnType>; + +const queries = { + findByLabelText, +}; + +type MapQueries = { + [P in keyof Q]: Q[P]; +}; From 1c744ca4be0834b24f0f1df555e267223c48e614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 13 Jul 2024 20:57:18 +0200 Subject: [PATCH 4/7] add an extra test case --- ...nferenceContextualReturnTypeUnion3.symbols | 146 +++++++++++ .../inferenceContextualReturnTypeUnion3.types | 237 ++++++++++++++++++ .../inferenceContextualReturnTypeUnion3.ts | 44 ++++ 3 files changed, 427 insertions(+) create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion3.symbols create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion3.types create mode 100644 tests/cases/compiler/inferenceContextualReturnTypeUnion3.ts diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion3.symbols b/tests/baselines/reference/inferenceContextualReturnTypeUnion3.symbols new file mode 100644 index 0000000000000..43c94f2219b10 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion3.symbols @@ -0,0 +1,146 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion3.ts] //// + +=== inferenceContextualReturnTypeUnion3.ts === +declare function deprecate( +>deprecate : Symbol(deprecate, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 0)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 27)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.decorators.d.ts, --, --)) + + fn: T, +>fn : Symbol(fn, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 47)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 27)) + + msg: string, +>msg : Symbol(msg, Decl(inferenceContextualReturnTypeUnion3.ts, 1, 8)) + + code?: string, +>code : Symbol(code, Decl(inferenceContextualReturnTypeUnion3.ts, 2, 14)) + +): T; +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 27)) + +const soonFrozenObjectDeprecation = ( +>soonFrozenObjectDeprecation : Symbol(soonFrozenObjectDeprecation, Decl(inferenceContextualReturnTypeUnion3.ts, 6, 5)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion3.ts, 6, 37)) + + obj: T, +>obj : Symbol(obj, Decl(inferenceContextualReturnTypeUnion3.ts, 6, 55)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion3.ts, 6, 37)) + + name: string, +>name : Symbol(name, Decl(inferenceContextualReturnTypeUnion3.ts, 7, 9)) + + code: string, +>code : Symbol(code, Decl(inferenceContextualReturnTypeUnion3.ts, 8, 15)) + + note = "", +>note : Symbol(note, Decl(inferenceContextualReturnTypeUnion3.ts, 9, 15)) + +): T => { +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion3.ts, 6, 37)) + + const message = `${name} will be frozen in future, all modifications are deprecated.${ +>message : Symbol(message, Decl(inferenceContextualReturnTypeUnion3.ts, 12, 7)) +>name : Symbol(name, Decl(inferenceContextualReturnTypeUnion3.ts, 7, 9)) + + note && `\n${note}` +>note : Symbol(note, Decl(inferenceContextualReturnTypeUnion3.ts, 9, 15)) +>note : Symbol(note, Decl(inferenceContextualReturnTypeUnion3.ts, 9, 15)) + + }`; + return new Proxy(obj, { +>Proxy : Symbol(Proxy, Decl(lib.es2015.proxy.d.ts, --, --)) +>obj : Symbol(obj, Decl(inferenceContextualReturnTypeUnion3.ts, 6, 55)) + + set: deprecate( +>set : Symbol(set, Decl(inferenceContextualReturnTypeUnion3.ts, 15, 25)) +>deprecate : Symbol(deprecate, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 0)) + + (target, property, value, receiver) => +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 7)) +>property : Symbol(property, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 14)) +>value : Symbol(value, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 24)) +>receiver : Symbol(receiver, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 31)) + + Reflect.set(target, property, value, receiver), +>Reflect.set : Symbol(Reflect.set, Decl(lib.es2015.reflect.d.ts, --, --), Decl(lib.es2015.reflect.d.ts, --, --)) +>Reflect : Symbol(Reflect, Decl(lib.es2015.reflect.d.ts, --, --)) +>set : Symbol(Reflect.set, Decl(lib.es2015.reflect.d.ts, --, --), Decl(lib.es2015.reflect.d.ts, --, --)) +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 7)) +>property : Symbol(property, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 14)) +>value : Symbol(value, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 24)) +>receiver : Symbol(receiver, Decl(inferenceContextualReturnTypeUnion3.ts, 17, 31)) + + message, +>message : Symbol(message, Decl(inferenceContextualReturnTypeUnion3.ts, 12, 7)) + + code, +>code : Symbol(code, Decl(inferenceContextualReturnTypeUnion3.ts, 8, 15)) + + ), + defineProperty: deprecate( +>defineProperty : Symbol(defineProperty, Decl(inferenceContextualReturnTypeUnion3.ts, 21, 6)) +>deprecate : Symbol(deprecate, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 0)) + + (target, property, descriptor) => +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 23, 7)) +>property : Symbol(property, Decl(inferenceContextualReturnTypeUnion3.ts, 23, 14)) +>descriptor : Symbol(descriptor, Decl(inferenceContextualReturnTypeUnion3.ts, 23, 24)) + + Reflect.defineProperty(target, property, descriptor), +>Reflect.defineProperty : Symbol(Reflect.defineProperty, Decl(lib.es2015.reflect.d.ts, --, --)) +>Reflect : Symbol(Reflect, Decl(lib.es2015.reflect.d.ts, --, --)) +>defineProperty : Symbol(Reflect.defineProperty, Decl(lib.es2015.reflect.d.ts, --, --)) +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 23, 7)) +>property : Symbol(property, Decl(inferenceContextualReturnTypeUnion3.ts, 23, 14)) +>descriptor : Symbol(descriptor, Decl(inferenceContextualReturnTypeUnion3.ts, 23, 24)) + + message, +>message : Symbol(message, Decl(inferenceContextualReturnTypeUnion3.ts, 12, 7)) + + code, +>code : Symbol(code, Decl(inferenceContextualReturnTypeUnion3.ts, 8, 15)) + + ), + deleteProperty: deprecate( +>deleteProperty : Symbol(deleteProperty, Decl(inferenceContextualReturnTypeUnion3.ts, 27, 6)) +>deprecate : Symbol(deprecate, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 0)) + + (target, property) => Reflect.deleteProperty(target, property), +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 29, 7)) +>property : Symbol(property, Decl(inferenceContextualReturnTypeUnion3.ts, 29, 14)) +>Reflect.deleteProperty : Symbol(Reflect.deleteProperty, Decl(lib.es2015.reflect.d.ts, --, --)) +>Reflect : Symbol(Reflect, Decl(lib.es2015.reflect.d.ts, --, --)) +>deleteProperty : Symbol(Reflect.deleteProperty, Decl(lib.es2015.reflect.d.ts, --, --)) +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 29, 7)) +>property : Symbol(property, Decl(inferenceContextualReturnTypeUnion3.ts, 29, 14)) + + message, +>message : Symbol(message, Decl(inferenceContextualReturnTypeUnion3.ts, 12, 7)) + + code, +>code : Symbol(code, Decl(inferenceContextualReturnTypeUnion3.ts, 8, 15)) + + ), + setPrototypeOf: deprecate( +>setPrototypeOf : Symbol(setPrototypeOf, Decl(inferenceContextualReturnTypeUnion3.ts, 32, 6)) +>deprecate : Symbol(deprecate, Decl(inferenceContextualReturnTypeUnion3.ts, 0, 0)) + + (target, proto) => Reflect.setPrototypeOf(target, proto), +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 34, 7)) +>proto : Symbol(proto, Decl(inferenceContextualReturnTypeUnion3.ts, 34, 14)) +>Reflect.setPrototypeOf : Symbol(Reflect.setPrototypeOf, Decl(lib.es2015.reflect.d.ts, --, --)) +>Reflect : Symbol(Reflect, Decl(lib.es2015.reflect.d.ts, --, --)) +>setPrototypeOf : Symbol(Reflect.setPrototypeOf, Decl(lib.es2015.reflect.d.ts, --, --)) +>target : Symbol(target, Decl(inferenceContextualReturnTypeUnion3.ts, 34, 7)) +>proto : Symbol(proto, Decl(inferenceContextualReturnTypeUnion3.ts, 34, 14)) + + message, +>message : Symbol(message, Decl(inferenceContextualReturnTypeUnion3.ts, 12, 7)) + + code, +>code : Symbol(code, Decl(inferenceContextualReturnTypeUnion3.ts, 8, 15)) + + ), + }); +}; diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion3.types b/tests/baselines/reference/inferenceContextualReturnTypeUnion3.types new file mode 100644 index 0000000000000..538f7397a0320 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion3.types @@ -0,0 +1,237 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion3.ts] //// + +=== inferenceContextualReturnTypeUnion3.ts === +declare function deprecate( +>deprecate : (fn: T, msg: string, code?: string) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^ + + fn: T, +>fn : T +> : ^ + + msg: string, +>msg : string +> : ^^^^^^ + + code?: string, +>code : string | undefined +> : ^^^^^^^^^^^^^^^^^^ + +): T; + +const soonFrozenObjectDeprecation = ( +>soonFrozenObjectDeprecation : (obj: T, name: string, code: string, note?: string) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^^^^^^ +>( obj: T, name: string, code: string, note = "",): T => { const message = `${name} will be frozen in future, all modifications are deprecated.${ note && `\n${note}` }`; return new Proxy(obj, { set: deprecate( (target, property, value, receiver) => Reflect.set(target, property, value, receiver), message, code, ), defineProperty: deprecate( (target, property, descriptor) => Reflect.defineProperty(target, property, descriptor), message, code, ), deleteProperty: deprecate( (target, property) => Reflect.deleteProperty(target, property), message, code, ), setPrototypeOf: deprecate( (target, proto) => Reflect.setPrototypeOf(target, proto), message, code, ), });} : (obj: T, name: string, code: string, note?: string) => T +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^^^^^^ + + obj: T, +>obj : T +> : ^ + + name: string, +>name : string +> : ^^^^^^ + + code: string, +>code : string +> : ^^^^^^ + + note = "", +>note : string +> : ^^^^^^ +>"" : "" +> : ^^ + +): T => { + const message = `${name} will be frozen in future, all modifications are deprecated.${ +>message : string +> : ^^^^^^ +>`${name} will be frozen in future, all modifications are deprecated.${ note && `\n${note}` }` : string +> : ^^^^^^ +>name : string +> : ^^^^^^ + + note && `\n${note}` +>note && `\n${note}` : string +> : ^^^^^^ +>note : string +> : ^^^^^^ +>`\n${note}` : string +> : ^^^^^^ +>note : string +> : ^^^^^^ + + }`; + return new Proxy(obj, { +>new Proxy(obj, { set: deprecate( (target, property, value, receiver) => Reflect.set(target, property, value, receiver), message, code, ), defineProperty: deprecate( (target, property, descriptor) => Reflect.defineProperty(target, property, descriptor), message, code, ), deleteProperty: deprecate( (target, property) => Reflect.deleteProperty(target, property), message, code, ), setPrototypeOf: deprecate( (target, proto) => Reflect.setPrototypeOf(target, proto), message, code, ), }) : T +> : ^ +>Proxy : ProxyConstructor +> : ^^^^^^^^^^^^^^^^ +>obj : T +> : ^ +>{ set: deprecate( (target, property, value, receiver) => Reflect.set(target, property, value, receiver), message, code, ), defineProperty: deprecate( (target, property, descriptor) => Reflect.defineProperty(target, property, descriptor), message, code, ), deleteProperty: deprecate( (target, property) => Reflect.deleteProperty(target, property), message, code, ), setPrototypeOf: deprecate( (target, proto) => Reflect.setPrototypeOf(target, proto), message, code, ), } : { set: (target: T, property: string | symbol, value: any, receiver: any) => boolean; defineProperty: (target: T, property: string | symbol, descriptor: PropertyDescriptor) => boolean; deleteProperty: (target: T, property: string | symbol) => boolean; setPrototypeOf: (target: T, proto: object | null) => boolean; } +> : ^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + set: deprecate( +>set : (target: T, property: string | symbol, value: any, receiver: any) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^ +>deprecate( (target, property, value, receiver) => Reflect.set(target, property, value, receiver), message, code, ) : (target: T, property: string | symbol, value: any, receiver: any) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^ +>deprecate : (fn: T_1, msg: string, code?: string) => T_1 +> : ^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^ + + (target, property, value, receiver) => +>(target, property, value, receiver) => Reflect.set(target, property, value, receiver) : (target: T, property: string | symbol, value: any, receiver: any) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^ +>target : T +> : ^ +>property : string | symbol +> : ^^^^^^^^^^^^^^^ +>value : any +>receiver : any + + Reflect.set(target, property, value, receiver), +>Reflect.set(target, property, value, receiver) : boolean +> : ^^^^^^^ +>Reflect.set : { (target: T_1, propertyKey: P, value: P extends keyof T_1 ? T_1[P] : any, receiver?: any): boolean; (target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean; } +> : ^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ +>Reflect : typeof Reflect +> : ^^^^^^^^^^^^^^ +>set : { (target: T_1, propertyKey: P, value: P extends keyof T_1 ? T_1[P] : any, receiver?: any): boolean; (target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean; } +> : ^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ +>target : T +> : ^ +>property : string | symbol +> : ^^^^^^^^^^^^^^^ +>value : any +>receiver : any + + message, +>message : string +> : ^^^^^^ + + code, +>code : string +> : ^^^^^^ + + ), + defineProperty: deprecate( +>defineProperty : (target: T, property: string | symbol, descriptor: PropertyDescriptor) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>deprecate( (target, property, descriptor) => Reflect.defineProperty(target, property, descriptor), message, code, ) : (target: T, property: string | symbol, descriptor: PropertyDescriptor) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>deprecate : (fn: T_1, msg: string, code?: string) => T_1 +> : ^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^ + + (target, property, descriptor) => +>(target, property, descriptor) => Reflect.defineProperty(target, property, descriptor) : (target: T, property: string | symbol, descriptor: PropertyDescriptor) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>target : T +> : ^ +>property : string | symbol +> : ^^^^^^^^^^^^^^^ +>descriptor : PropertyDescriptor +> : ^^^^^^^^^^^^^^^^^^ + + Reflect.defineProperty(target, property, descriptor), +>Reflect.defineProperty(target, property, descriptor) : boolean +> : ^^^^^^^ +>Reflect.defineProperty : (target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor & ThisType) => boolean +> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>Reflect : typeof Reflect +> : ^^^^^^^^^^^^^^ +>defineProperty : (target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor & ThisType) => boolean +> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>target : T +> : ^ +>property : string | symbol +> : ^^^^^^^^^^^^^^^ +>descriptor : PropertyDescriptor +> : ^^^^^^^^^^^^^^^^^^ + + message, +>message : string +> : ^^^^^^ + + code, +>code : string +> : ^^^^^^ + + ), + deleteProperty: deprecate( +>deleteProperty : (target: T, property: string | symbol) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>deprecate( (target, property) => Reflect.deleteProperty(target, property), message, code, ) : (target: T, property: string | symbol) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>deprecate : (fn: T_1, msg: string, code?: string) => T_1 +> : ^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^ + + (target, property) => Reflect.deleteProperty(target, property), +>(target, property) => Reflect.deleteProperty(target, property) : (target: T, property: string | symbol) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>target : T +> : ^ +>property : string | symbol +> : ^^^^^^^^^^^^^^^ +>Reflect.deleteProperty(target, property) : boolean +> : ^^^^^^^ +>Reflect.deleteProperty : (target: object, propertyKey: PropertyKey) => boolean +> : ^ ^^ ^^ ^^ ^^^^^ +>Reflect : typeof Reflect +> : ^^^^^^^^^^^^^^ +>deleteProperty : (target: object, propertyKey: PropertyKey) => boolean +> : ^ ^^ ^^ ^^ ^^^^^ +>target : T +> : ^ +>property : string | symbol +> : ^^^^^^^^^^^^^^^ + + message, +>message : string +> : ^^^^^^ + + code, +>code : string +> : ^^^^^^ + + ), + setPrototypeOf: deprecate( +>setPrototypeOf : (target: T, proto: object | null) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>deprecate( (target, proto) => Reflect.setPrototypeOf(target, proto), message, code, ) : (target: T, proto: object | null) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>deprecate : (fn: T_1, msg: string, code?: string) => T_1 +> : ^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^ + + (target, proto) => Reflect.setPrototypeOf(target, proto), +>(target, proto) => Reflect.setPrototypeOf(target, proto) : (target: T, proto: object | null) => boolean +> : ^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>target : T +> : ^ +>proto : object | null +> : ^^^^^^^^^^^^^ +>Reflect.setPrototypeOf(target, proto) : boolean +> : ^^^^^^^ +>Reflect.setPrototypeOf : (target: object, proto: object | null) => boolean +> : ^ ^^ ^^ ^^ ^^^^^ +>Reflect : typeof Reflect +> : ^^^^^^^^^^^^^^ +>setPrototypeOf : (target: object, proto: object | null) => boolean +> : ^ ^^ ^^ ^^ ^^^^^ +>target : T +> : ^ +>proto : object | null +> : ^^^^^^^^^^^^^ + + message, +>message : string +> : ^^^^^^ + + code, +>code : string +> : ^^^^^^ + + ), + }); +}; diff --git a/tests/cases/compiler/inferenceContextualReturnTypeUnion3.ts b/tests/cases/compiler/inferenceContextualReturnTypeUnion3.ts new file mode 100644 index 0000000000000..195900bfc38f1 --- /dev/null +++ b/tests/cases/compiler/inferenceContextualReturnTypeUnion3.ts @@ -0,0 +1,44 @@ +// @strict: true +// @lib: esnext +// @noEmit: true + +declare function deprecate( + fn: T, + msg: string, + code?: string, +): T; + +const soonFrozenObjectDeprecation = ( + obj: T, + name: string, + code: string, + note = "", +): T => { + const message = `${name} will be frozen in future, all modifications are deprecated.${ + note && `\n${note}` + }`; + return new Proxy(obj, { + set: deprecate( + (target, property, value, receiver) => + Reflect.set(target, property, value, receiver), + message, + code, + ), + defineProperty: deprecate( + (target, property, descriptor) => + Reflect.defineProperty(target, property, descriptor), + message, + code, + ), + deleteProperty: deprecate( + (target, property) => Reflect.deleteProperty(target, property), + message, + code, + ), + setPrototypeOf: deprecate( + (target, proto) => Reflect.setPrototypeOf(target, proto), + message, + code, + ), + }); +}; \ No newline at end of file From 24f5964f6d86597345116a6118e13b89d2a475e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 13 Jul 2024 23:51:14 +0200 Subject: [PATCH 5/7] dont forget about the fallback type --- src/compiler/checker.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2316677e692ad..ad66db008afd8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26893,17 +26893,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constraint = getConstraintOfTypeParameter(inference.typeParameter); if (constraint) { const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper); - if (!inferredType) { - inference.inferredType = instantiatedConstraint; + if (inference.priority! & InferencePriority.ReturnType) { + inference.inferredType = (inferredType && filterContextualInferredType(inferredType, instantiatedConstraint)) ?? (fallbackType && filterContextualInferredType(fallbackType, instantiatedConstraint)) ?? instantiatedConstraint; } - else { - if (inference.priority! & InferencePriority.ReturnType) { - inference.inferredType = filterContextualInferredType(inferredType, instantiatedConstraint) ?? (fallbackType && filterContextualInferredType(fallbackType, instantiatedConstraint)) ?? instantiatedConstraint; - } - else if (!context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { - // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint. - inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; - } + else if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { + // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint. + inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; } } } From 97c164dcd7cc0449f63663d28fee827026bf5eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 9 Sep 2024 12:33:02 +0200 Subject: [PATCH 6/7] add extra test case --- ...nferenceContextualReturnTypeUnion4.symbols | 37 +++++++++++++++++++ .../inferenceContextualReturnTypeUnion4.types | 36 ++++++++++++++++++ .../inferenceContextualReturnTypeUnion4.ts | 17 +++++++++ 3 files changed, 90 insertions(+) create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion4.symbols create mode 100644 tests/baselines/reference/inferenceContextualReturnTypeUnion4.types create mode 100644 tests/cases/compiler/inferenceContextualReturnTypeUnion4.ts diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion4.symbols b/tests/baselines/reference/inferenceContextualReturnTypeUnion4.symbols new file mode 100644 index 0000000000000..c4d39728acb77 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion4.symbols @@ -0,0 +1,37 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion4.ts] //// + +=== inferenceContextualReturnTypeUnion4.ts === +// https://github.com/microsoft/TypeScript/issues/57905 + +export abstract class Storage { +>Storage : Symbol(Storage, Decl(inferenceContextualReturnTypeUnion4.ts, 0, 0)) + + abstract get(): T | Promise; +>get : Symbol(Storage.get, Decl(inferenceContextualReturnTypeUnion4.ts, 2, 31)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion4.ts, 3, 17)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion4.ts, 3, 17)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion4.ts, 3, 17)) +} + +export abstract class SyncStorage extends Storage { +>SyncStorage : Symbol(SyncStorage, Decl(inferenceContextualReturnTypeUnion4.ts, 4, 1)) +>Storage : Symbol(Storage, Decl(inferenceContextualReturnTypeUnion4.ts, 0, 0)) + + abstract override get(): T; +>get : Symbol(SyncStorage.get, Decl(inferenceContextualReturnTypeUnion4.ts, 6, 51)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion4.ts, 7, 26)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion4.ts, 7, 26)) +} + +export abstract class ASyncStorage extends Storage { +>ASyncStorage : Symbol(ASyncStorage, Decl(inferenceContextualReturnTypeUnion4.ts, 8, 1)) +>Storage : Symbol(Storage, Decl(inferenceContextualReturnTypeUnion4.ts, 0, 0)) + + abstract override get(): Promise; +>get : Symbol(ASyncStorage.get, Decl(inferenceContextualReturnTypeUnion4.ts, 10, 52)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion4.ts, 11, 26)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(inferenceContextualReturnTypeUnion4.ts, 11, 26)) +} + diff --git a/tests/baselines/reference/inferenceContextualReturnTypeUnion4.types b/tests/baselines/reference/inferenceContextualReturnTypeUnion4.types new file mode 100644 index 0000000000000..af2d1a21a96d5 --- /dev/null +++ b/tests/baselines/reference/inferenceContextualReturnTypeUnion4.types @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/inferenceContextualReturnTypeUnion4.ts] //// + +=== inferenceContextualReturnTypeUnion4.ts === +// https://github.com/microsoft/TypeScript/issues/57905 + +export abstract class Storage { +>Storage : Storage +> : ^^^^^^^ + + abstract get(): T | Promise; +>get : () => T | Promise +> : ^ ^^^^^^^^^ ^^^^^^^ +} + +export abstract class SyncStorage extends Storage { +>SyncStorage : SyncStorage +> : ^^^^^^^^^^^ +>Storage : Storage +> : ^^^^^^^ + + abstract override get(): T; +>get : () => T +> : ^ ^^^^^^^^^ ^^^^^^^ +} + +export abstract class ASyncStorage extends Storage { +>ASyncStorage : ASyncStorage +> : ^^^^^^^^^^^^ +>Storage : Storage +> : ^^^^^^^ + + abstract override get(): Promise; +>get : () => Promise +> : ^ ^^^^^^^^^ ^^^^^^^ +} + diff --git a/tests/cases/compiler/inferenceContextualReturnTypeUnion4.ts b/tests/cases/compiler/inferenceContextualReturnTypeUnion4.ts new file mode 100644 index 0000000000000..cbc69df35b2af --- /dev/null +++ b/tests/cases/compiler/inferenceContextualReturnTypeUnion4.ts @@ -0,0 +1,17 @@ +// @strict: true +// @lib: esnext +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/57905 + +export abstract class Storage { + abstract get(): T | Promise; +} + +export abstract class SyncStorage extends Storage { + abstract override get(): T; +} + +export abstract class ASyncStorage extends Storage { + abstract override get(): Promise; +} From 35e0002761a2f5b9d0598f907cf87f8955ac7038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 3 Dec 2025 17:03:19 +0100 Subject: [PATCH 7/7] match ts-go changes --- src/compiler/checker.ts | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e0069c4e95db7..bfa81f6964601 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27576,27 +27576,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constraint = getConstraintOfTypeParameter(inference.typeParameter); if (constraint) { const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper); - if (inference.priority! & InferencePriority.ReturnType) { - inference.inferredType = (inferredType && filterContextualInferredType(inferredType, instantiatedConstraint)) ?? (fallbackType && filterContextualInferredType(fallbackType, instantiatedConstraint)) ?? instantiatedConstraint; + if (inferredType) { + const constraintWithThis = getTypeWithThisArgument(instantiatedConstraint, inferredType); + if (!context.compareTypes(inferredType, constraintWithThis)) { + // If we have a pure return type inference, we may succeed by removing constituents of the inferred type + // that aren't assignable to the constraint type (pure return type inferences are speculation anyway). + const filteredByConstraint = inference.priority === InferencePriority.ReturnType ? filterType(inferredType, t => !!context.compareTypes(t, constraintWithThis)) : neverType; + inferredType = !(filteredByConstraint.flags & TypeFlags.Never) ? filteredByConstraint : undefined; + } } - else if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { + if (!inferredType) { // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint. - inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; + inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; } + inference.inferredType = inferredType; } clearActiveMapperCaches(); } return inference.inferredType; - - function filterContextualInferredType(inferredType: Type, constraint: Type) { - if (inferredType.flags & TypeFlags.Never) { - return inferredType; - } - const constraintWithThisArgument = getTypeWithThisArgument(constraint, inferredType); - const applicableByConstraint = filterType(inferredType, t => !!context.compareTypes(t, constraintWithThisArgument)); - return !(applicableByConstraint.flags & TypeFlags.Never) ? applicableByConstraint : undefined; - } } function getDefaultTypeArgumentType(isInJavaScriptFile: boolean): Type {