Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27576,10 +27576,20 @@ 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 (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;
}
}
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();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//// [tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts] ////

=== inferenceContextualReturnTypeUnion1.ts ===
// https://github.com/microsoft/TypeScript/issues/50719

declare function useCallback1<T extends Function>(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, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.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<T extends (...args: any[]) => 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))

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//// [tests/cases/compiler/inferenceContextualReturnTypeUnion1.ts] ////

=== inferenceContextualReturnTypeUnion1.ts ===
// https://github.com/microsoft/TypeScript/issues/50719

declare function useCallback1<T extends Function>(fn: T): T;
>useCallback1 : <T extends Function>(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 : <T extends Function>(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 : <T extends Function>(fn: T) => T
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>(x) => {} : (x: number) => void
> : ^ ^^^^^^^^^^^^^^^^^
>x : number
> : ^^^^^^

// https://github.com/microsoft/TypeScript/issues/41461

declare function useCallback2<T extends (...args: any[]) => any>(
>useCallback2 : <T extends (...args: any[]) => 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 : <T extends (...args: any[]) => any>(callback: T) => T
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>(x) => {} : (x: string) => void
> : ^ ^^^^^^^^^^^^^^^^^
>x : string
> : ^^^^^^

Original file line number Diff line number Diff line change
@@ -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<HTMLElement[]>
>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<HTMLElement>
>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<T extends HTMLElement = HTMLElement> = (
>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<T>;
>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<T extends HTMLElement = HTMLElement>(
>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<FindByText<T>>
>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<FindByText<T>>;
>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<Q extends Queries = typeof queries> = {
>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))

};

Original file line number Diff line number Diff line change
@@ -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<HTMLElement[]>
| Promise<HTMLElement>
| null;

interface Queries {
[T: string]: Query;
>T : string
> : ^^^^^^
}

type FindByText<T extends HTMLElement = HTMLElement> = (
>FindByText : FindByText<T>
> : ^^^^^^^^^^^^^

container: HTMLElement,
>container : HTMLElement
> : ^^^^^^^^^^^

text: string,
>text : string
> : ^^^^^^

) => Promise<T>;

declare function findByLabelText<T extends HTMLElement = HTMLElement>(
>findByLabelText : <T extends HTMLElement = HTMLElement>(container: HTMLElement, text: string) => ReturnType<FindByText<T>>
> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

...args: Parameters<FindByText<T>>
>args : [container: HTMLElement, text: string]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

): ReturnType<FindByText<T>>;

const queries = {
>queries : { findByLabelText: <T extends HTMLElement = HTMLElement>(container: HTMLElement, text: string) => ReturnType<FindByText<T>>; }
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^
>{ findByLabelText,} : { findByLabelText: <T extends HTMLElement = HTMLElement>(container: HTMLElement, text: string) => ReturnType<FindByText<T>>; }
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^

findByLabelText,
>findByLabelText : <T extends HTMLElement = HTMLElement>(container: HTMLElement, text: string) => ReturnType<FindByText<T>>
> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

};

type MapQueries<Q extends Queries = typeof queries> = {
>MapQueries : MapQueries<Q>
> : ^^^^^^^^^^^^^
>queries : { findByLabelText: <T extends HTMLElement = HTMLElement>(container: HTMLElement, text: string) => ReturnType<FindByText<T>>; }
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^

[P in keyof Q]: Q[P];
};

Loading