mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 11:35:42 -06:00
Infer from annotated return type nodes before assigning contextual parameter types (#60964)
This commit is contained in:
parent
12c232333b
commit
0d016920e6
@ -37870,7 +37870,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : fallbackType;
|
||||
}
|
||||
|
||||
function inferFromAnnotatedParameters(signature: Signature, context: Signature, inferenceContext: InferenceContext) {
|
||||
function inferFromAnnotatedParametersAndReturn(signature: Signature, context: Signature, inferenceContext: InferenceContext) {
|
||||
const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0);
|
||||
for (let i = 0; i < len; i++) {
|
||||
const declaration = signature.parameters[i].valueDeclaration as ParameterDeclaration;
|
||||
@ -37881,6 +37881,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
inferTypes(inferenceContext.inferences, source, target);
|
||||
}
|
||||
}
|
||||
const typeNode = signature.declaration && getEffectiveReturnTypeNode(signature.declaration);
|
||||
if (typeNode) {
|
||||
const source = getTypeFromTypeNode(typeNode);
|
||||
const target = getReturnTypeOfSignature(context);
|
||||
inferTypes(inferenceContext.inferences, source, target);
|
||||
}
|
||||
}
|
||||
|
||||
function assignContextualParameterTypes(signature: Signature, context: Signature) {
|
||||
@ -38878,7 +38884,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const inferenceContext = getInferenceContext(node);
|
||||
let instantiatedContextualSignature: Signature | undefined;
|
||||
if (checkMode && checkMode & CheckMode.Inferential) {
|
||||
inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!);
|
||||
inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!);
|
||||
const restType = getEffectiveRestType(contextualSignature);
|
||||
if (restType && restType.flags & TypeFlags.TypeParameter) {
|
||||
instantiatedContextualSignature = instantiateSignature(contextualSignature, inferenceContext!.nonFixingMapper);
|
||||
@ -38896,7 +38902,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
else if (contextualSignature && !node.typeParameters && contextualSignature.parameters.length > node.parameters.length) {
|
||||
const inferenceContext = getInferenceContext(node);
|
||||
if (checkMode && checkMode & CheckMode.Inferential) {
|
||||
inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!);
|
||||
inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!);
|
||||
}
|
||||
}
|
||||
if (contextualSignature && !getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) {
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
inferFromAnnotatedReturn1.ts(4,36): error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== inferFromAnnotatedReturn1.ts (1 errors) ====
|
||||
declare function test<T>(cb: (arg: T) => T): T;
|
||||
|
||||
const res1 = test((arg): number => 1); // ok
|
||||
const res2 = test((arg): number => 'foo'); // error
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
|
||||
export declare function linkedSignal<S, D>(options: {
|
||||
source: () => S;
|
||||
computation: (source: NoInfer<D>) => D;
|
||||
}): D;
|
||||
|
||||
const signal = linkedSignal({
|
||||
source: () => 3,
|
||||
computation: (s): number => 3,
|
||||
});
|
||||
|
||||
class Foo<T, R> {
|
||||
constructor(readonly cb: (t: T, _: { x: number; other: NoInfer<R> }) => R) {}
|
||||
}
|
||||
|
||||
const _1 = new Foo((name: string, { x }): { name: string; x: number } => ({
|
||||
name,
|
||||
x,
|
||||
}));
|
||||
|
||||
88
tests/baselines/reference/inferFromAnnotatedReturn1.symbols
Normal file
88
tests/baselines/reference/inferFromAnnotatedReturn1.symbols
Normal file
@ -0,0 +1,88 @@
|
||||
//// [tests/cases/compiler/inferFromAnnotatedReturn1.ts] ////
|
||||
|
||||
=== inferFromAnnotatedReturn1.ts ===
|
||||
declare function test<T>(cb: (arg: T) => T): T;
|
||||
>test : Symbol(test, Decl(inferFromAnnotatedReturn1.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(inferFromAnnotatedReturn1.ts, 0, 22))
|
||||
>cb : Symbol(cb, Decl(inferFromAnnotatedReturn1.ts, 0, 25))
|
||||
>arg : Symbol(arg, Decl(inferFromAnnotatedReturn1.ts, 0, 30))
|
||||
>T : Symbol(T, Decl(inferFromAnnotatedReturn1.ts, 0, 22))
|
||||
>T : Symbol(T, Decl(inferFromAnnotatedReturn1.ts, 0, 22))
|
||||
>T : Symbol(T, Decl(inferFromAnnotatedReturn1.ts, 0, 22))
|
||||
|
||||
const res1 = test((arg): number => 1); // ok
|
||||
>res1 : Symbol(res1, Decl(inferFromAnnotatedReturn1.ts, 2, 5))
|
||||
>test : Symbol(test, Decl(inferFromAnnotatedReturn1.ts, 0, 0))
|
||||
>arg : Symbol(arg, Decl(inferFromAnnotatedReturn1.ts, 2, 19))
|
||||
|
||||
const res2 = test((arg): number => 'foo'); // error
|
||||
>res2 : Symbol(res2, Decl(inferFromAnnotatedReturn1.ts, 3, 5))
|
||||
>test : Symbol(test, Decl(inferFromAnnotatedReturn1.ts, 0, 0))
|
||||
>arg : Symbol(arg, Decl(inferFromAnnotatedReturn1.ts, 3, 19))
|
||||
|
||||
export declare function linkedSignal<S, D>(options: {
|
||||
>linkedSignal : Symbol(linkedSignal, Decl(inferFromAnnotatedReturn1.ts, 3, 42))
|
||||
>S : Symbol(S, Decl(inferFromAnnotatedReturn1.ts, 5, 37))
|
||||
>D : Symbol(D, Decl(inferFromAnnotatedReturn1.ts, 5, 39))
|
||||
>options : Symbol(options, Decl(inferFromAnnotatedReturn1.ts, 5, 43))
|
||||
|
||||
source: () => S;
|
||||
>source : Symbol(source, Decl(inferFromAnnotatedReturn1.ts, 5, 53))
|
||||
>S : Symbol(S, Decl(inferFromAnnotatedReturn1.ts, 5, 37))
|
||||
|
||||
computation: (source: NoInfer<D>) => D;
|
||||
>computation : Symbol(computation, Decl(inferFromAnnotatedReturn1.ts, 6, 18))
|
||||
>source : Symbol(source, Decl(inferFromAnnotatedReturn1.ts, 7, 16))
|
||||
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
|
||||
>D : Symbol(D, Decl(inferFromAnnotatedReturn1.ts, 5, 39))
|
||||
>D : Symbol(D, Decl(inferFromAnnotatedReturn1.ts, 5, 39))
|
||||
|
||||
}): D;
|
||||
>D : Symbol(D, Decl(inferFromAnnotatedReturn1.ts, 5, 39))
|
||||
|
||||
const signal = linkedSignal({
|
||||
>signal : Symbol(signal, Decl(inferFromAnnotatedReturn1.ts, 10, 5))
|
||||
>linkedSignal : Symbol(linkedSignal, Decl(inferFromAnnotatedReturn1.ts, 3, 42))
|
||||
|
||||
source: () => 3,
|
||||
>source : Symbol(source, Decl(inferFromAnnotatedReturn1.ts, 10, 29))
|
||||
|
||||
computation: (s): number => 3,
|
||||
>computation : Symbol(computation, Decl(inferFromAnnotatedReturn1.ts, 11, 18))
|
||||
>s : Symbol(s, Decl(inferFromAnnotatedReturn1.ts, 12, 16))
|
||||
|
||||
});
|
||||
|
||||
class Foo<T, R> {
|
||||
>Foo : Symbol(Foo, Decl(inferFromAnnotatedReturn1.ts, 13, 3))
|
||||
>T : Symbol(T, Decl(inferFromAnnotatedReturn1.ts, 15, 10))
|
||||
>R : Symbol(R, Decl(inferFromAnnotatedReturn1.ts, 15, 12))
|
||||
|
||||
constructor(readonly cb: (t: T, _: { x: number; other: NoInfer<R> }) => R) {}
|
||||
>cb : Symbol(Foo.cb, Decl(inferFromAnnotatedReturn1.ts, 16, 14))
|
||||
>t : Symbol(t, Decl(inferFromAnnotatedReturn1.ts, 16, 28))
|
||||
>T : Symbol(T, Decl(inferFromAnnotatedReturn1.ts, 15, 10))
|
||||
>_ : Symbol(_, Decl(inferFromAnnotatedReturn1.ts, 16, 33))
|
||||
>x : Symbol(x, Decl(inferFromAnnotatedReturn1.ts, 16, 38))
|
||||
>other : Symbol(other, Decl(inferFromAnnotatedReturn1.ts, 16, 49))
|
||||
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
|
||||
>R : Symbol(R, Decl(inferFromAnnotatedReturn1.ts, 15, 12))
|
||||
>R : Symbol(R, Decl(inferFromAnnotatedReturn1.ts, 15, 12))
|
||||
}
|
||||
|
||||
const _1 = new Foo((name: string, { x }): { name: string; x: number } => ({
|
||||
>_1 : Symbol(_1, Decl(inferFromAnnotatedReturn1.ts, 19, 5))
|
||||
>Foo : Symbol(Foo, Decl(inferFromAnnotatedReturn1.ts, 13, 3))
|
||||
>name : Symbol(name, Decl(inferFromAnnotatedReturn1.ts, 19, 20))
|
||||
>x : Symbol(x, Decl(inferFromAnnotatedReturn1.ts, 19, 35))
|
||||
>name : Symbol(name, Decl(inferFromAnnotatedReturn1.ts, 19, 43))
|
||||
>x : Symbol(x, Decl(inferFromAnnotatedReturn1.ts, 19, 57))
|
||||
|
||||
name,
|
||||
>name : Symbol(name, Decl(inferFromAnnotatedReturn1.ts, 19, 75))
|
||||
|
||||
x,
|
||||
>x : Symbol(x, Decl(inferFromAnnotatedReturn1.ts, 20, 7))
|
||||
|
||||
}));
|
||||
|
||||
136
tests/baselines/reference/inferFromAnnotatedReturn1.types
Normal file
136
tests/baselines/reference/inferFromAnnotatedReturn1.types
Normal file
@ -0,0 +1,136 @@
|
||||
//// [tests/cases/compiler/inferFromAnnotatedReturn1.ts] ////
|
||||
|
||||
=== inferFromAnnotatedReturn1.ts ===
|
||||
declare function test<T>(cb: (arg: T) => T): T;
|
||||
>test : <T>(cb: (arg: T) => T) => T
|
||||
> : ^ ^^ ^^ ^^^^^
|
||||
>cb : (arg: T) => T
|
||||
> : ^ ^^ ^^^^^
|
||||
>arg : T
|
||||
> : ^
|
||||
|
||||
const res1 = test((arg): number => 1); // ok
|
||||
>res1 : number
|
||||
> : ^^^^^^
|
||||
>test((arg): number => 1) : number
|
||||
> : ^^^^^^
|
||||
>test : <T>(cb: (arg: T) => T) => T
|
||||
> : ^ ^^ ^^ ^^^^^
|
||||
>(arg): number => 1 : (arg: number) => number
|
||||
> : ^ ^^^^^^^^^^^^^
|
||||
>arg : number
|
||||
> : ^^^^^^
|
||||
>1 : 1
|
||||
> : ^
|
||||
|
||||
const res2 = test((arg): number => 'foo'); // error
|
||||
>res2 : number
|
||||
> : ^^^^^^
|
||||
>test((arg): number => 'foo') : number
|
||||
> : ^^^^^^
|
||||
>test : <T>(cb: (arg: T) => T) => T
|
||||
> : ^ ^^ ^^ ^^^^^
|
||||
>(arg): number => 'foo' : (arg: number) => number
|
||||
> : ^ ^^^^^^^^^^^^^
|
||||
>arg : number
|
||||
> : ^^^^^^
|
||||
>'foo' : "foo"
|
||||
> : ^^^^^
|
||||
|
||||
export declare function linkedSignal<S, D>(options: {
|
||||
>linkedSignal : <S, D>(options: { source: () => S; computation: (source: NoInfer<D>) => D; }) => D
|
||||
> : ^ ^^ ^^ ^^ ^^^^^
|
||||
>options : { source: () => S; computation: (source: NoInfer<D>) => D; }
|
||||
> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^
|
||||
|
||||
source: () => S;
|
||||
>source : () => S
|
||||
> : ^^^^^^
|
||||
|
||||
computation: (source: NoInfer<D>) => D;
|
||||
>computation : (source: NoInfer<D>) => D
|
||||
> : ^ ^^ ^^^^^
|
||||
>source : NoInfer<D>
|
||||
> : ^^^^^^^^^^
|
||||
|
||||
}): D;
|
||||
|
||||
const signal = linkedSignal({
|
||||
>signal : number
|
||||
> : ^^^^^^
|
||||
>linkedSignal({ source: () => 3, computation: (s): number => 3,}) : number
|
||||
> : ^^^^^^
|
||||
>linkedSignal : <S, D>(options: { source: () => S; computation: (source: NoInfer<D>) => D; }) => D
|
||||
> : ^ ^^ ^^ ^^ ^^^^^
|
||||
>{ source: () => 3, computation: (s): number => 3,} : { source: () => number; computation: (s: number) => number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^
|
||||
|
||||
source: () => 3,
|
||||
>source : () => number
|
||||
> : ^^^^^^^^^^^^
|
||||
>() => 3 : () => number
|
||||
> : ^^^^^^^^^^^^
|
||||
>3 : 3
|
||||
> : ^
|
||||
|
||||
computation: (s): number => 3,
|
||||
>computation : (s: number) => number
|
||||
> : ^ ^^^^^^^^^^^^^
|
||||
>(s): number => 3 : (s: number) => number
|
||||
> : ^ ^^^^^^^^^^^^^
|
||||
>s : number
|
||||
> : ^^^^^^
|
||||
>3 : 3
|
||||
> : ^
|
||||
|
||||
});
|
||||
|
||||
class Foo<T, R> {
|
||||
>Foo : Foo<T, R>
|
||||
> : ^^^^^^^^^
|
||||
|
||||
constructor(readonly cb: (t: T, _: { x: number; other: NoInfer<R> }) => R) {}
|
||||
>cb : (t: T, _: { x: number; other: NoInfer<R>; }) => R
|
||||
> : ^ ^^ ^^ ^^ ^^^^^
|
||||
>t : T
|
||||
> : ^
|
||||
>_ : { x: number; other: NoInfer<R>; }
|
||||
> : ^^^^^ ^^^^^^^^^ ^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
>other : NoInfer<R>
|
||||
> : ^^^^^^^^^^
|
||||
}
|
||||
|
||||
const _1 = new Foo((name: string, { x }): { name: string; x: number } => ({
|
||||
>_1 : Foo<string, { name: string; x: number; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^
|
||||
>new Foo((name: string, { x }): { name: string; x: number } => ({ name, x,})) : Foo<string, { name: string; x: number; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^
|
||||
>Foo : typeof Foo
|
||||
> : ^^^^^^^^^^
|
||||
>(name: string, { x }): { name: string; x: number } => ({ name, x,}) : (name: string, { x }: { x: number; other: NoInfer<{ name: string; x: number; }>; }) => { name: string; x: number; }
|
||||
> : ^ ^^ ^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^
|
||||
>name : string
|
||||
> : ^^^^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
>name : string
|
||||
> : ^^^^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
>({ name, x,}) : { name: string; x: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>{ name, x,} : { name: string; x: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
name,
|
||||
>name : string
|
||||
> : ^^^^^^
|
||||
|
||||
x,
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
|
||||
}));
|
||||
|
||||
26
tests/cases/compiler/inferFromAnnotatedReturn1.ts
Normal file
26
tests/cases/compiler/inferFromAnnotatedReturn1.ts
Normal file
@ -0,0 +1,26 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
declare function test<T>(cb: (arg: T) => T): T;
|
||||
|
||||
const res1 = test((arg): number => 1); // ok
|
||||
const res2 = test((arg): number => 'foo'); // error
|
||||
|
||||
export declare function linkedSignal<S, D>(options: {
|
||||
source: () => S;
|
||||
computation: (source: NoInfer<D>) => D;
|
||||
}): D;
|
||||
|
||||
const signal = linkedSignal({
|
||||
source: () => 3,
|
||||
computation: (s): number => 3,
|
||||
});
|
||||
|
||||
class Foo<T, R> {
|
||||
constructor(readonly cb: (t: T, _: { x: number; other: NoInfer<R> }) => R) {}
|
||||
}
|
||||
|
||||
const _1 = new Foo((name: string, { x }): { name: string; x: number } => ({
|
||||
name,
|
||||
x,
|
||||
}));
|
||||
Loading…
x
Reference in New Issue
Block a user