Skip to content

Commit be49d9c

Browse files
committed
Allow non-generic return types to be read from single generic call signatures
1 parent d495200 commit be49d9c

8 files changed

+433
-8
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37716,17 +37716,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3771637716
}
3771737717
}
3771837718

37719-
function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) {
37719+
function getNonGenericReturnTypeOfSingleCallSignature(funcType: Type) {
3772037720
const signature = getSingleCallSignature(funcType);
37721-
if (signature && !signature.typeParameters) {
37722-
return getReturnTypeOfSignature(signature);
37721+
if (signature) {
37722+
const returnType = getReturnTypeOfSignature(signature);
37723+
if (!signature.typeParameters || !couldContainTypeVariables(returnType)) {
37724+
return returnType;
37725+
}
3772337726
}
3772437727
}
3772537728

3772637729
function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) {
3772737730
const funcType = checkExpression(expr.expression);
3772837731
const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
37729-
const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType);
37732+
const returnType = getNonGenericReturnTypeOfSingleCallSignature(funcType);
3773037733
return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType);
3773137734
}
3773237735

@@ -37775,7 +37778,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3777537778
// signature where we can just fetch the return type without checking the arguments.
3777637779
if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !isSymbolOrSymbolForCall(expr)) {
3777737780
return isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) :
37778-
getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression));
37781+
getNonGenericReturnTypeOfSingleCallSignature(checkNonNullExpression(expr.expression));
3777937782
}
3778037783
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
3778137784
return getTypeFromTypeNode((expr as TypeAssertion).type);

tests/baselines/reference/arrayFrom.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const inputALike: ArrayLike<A> = { length: 0 };
2929
const inputARand = getEither(inputA, inputALike);
3030
>inputARand : ArrayLike<A> | Iterable<A>
3131
>getEither(inputA, inputALike) : ArrayLike<A> | Iterable<A>
32-
>getEither : <T>(in1: Iterable<T>, in2: ArrayLike<T>) => ArrayLike<T> | Iterable<T>
32+
>getEither : <T>(in1: Iterable<T>, in2: ArrayLike<T>) => Iterable<T> | ArrayLike<T>
3333
>inputA : A[]
3434
>inputALike : ArrayLike<A>
3535

@@ -161,12 +161,12 @@ const result11: B[] = Array.from(inputASet, ({ a }): B => ({ b: a }));
161161
// the ?: as always taking the false branch, narrowing to ArrayLike<T>,
162162
// even when the type is written as : Iterable<T>|ArrayLike<T>
163163
function getEither<T> (in1: Iterable<T>, in2: ArrayLike<T>) {
164-
>getEither : <T>(in1: Iterable<T>, in2: ArrayLike<T>) => ArrayLike<T> | Iterable<T>
164+
>getEither : <T>(in1: Iterable<T>, in2: ArrayLike<T>) => Iterable<T> | ArrayLike<T>
165165
>in1 : Iterable<T>
166166
>in2 : ArrayLike<T>
167167

168168
return Math.random() > 0.5 ? in1 : in2;
169-
>Math.random() > 0.5 ? in1 : in2 : ArrayLike<T> | Iterable<T>
169+
>Math.random() > 0.5 ? in1 : in2 : Iterable<T> | ArrayLike<T>
170170
>Math.random() > 0.5 : boolean
171171
>Math.random() : number
172172
>Math.random : () => number
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
=== tests/cases/compiler/circularReferenceInReturnType.ts ===
2+
declare function fn1<T>(cb: () => T): string;
3+
>fn1 : Symbol(fn1, Decl(circularReferenceInReturnType.ts, 0, 0))
4+
>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 0, 21))
5+
>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 0, 24))
6+
>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 0, 21))
7+
8+
const res1 = fn1(() => res1);
9+
>res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 1, 5))
10+
>fn1 : Symbol(fn1, Decl(circularReferenceInReturnType.ts, 0, 0))
11+
>res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 1, 5))
12+
13+
declare function fn2<T>(): (cb: () => any) => (a: T) => void;
14+
>fn2 : Symbol(fn2, Decl(circularReferenceInReturnType.ts, 1, 29))
15+
>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 3, 21))
16+
>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 3, 28))
17+
>a : Symbol(a, Decl(circularReferenceInReturnType.ts, 3, 47))
18+
>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 3, 21))
19+
20+
const res2 = fn2()(() => res2);
21+
>res2 : Symbol(res2, Decl(circularReferenceInReturnType.ts, 4, 5))
22+
>fn2 : Symbol(fn2, Decl(circularReferenceInReturnType.ts, 1, 29))
23+
>res2 : Symbol(res2, Decl(circularReferenceInReturnType.ts, 4, 5))
24+
25+
declare function fn3<T>(): <T2>(cb: (arg: T2) => any) => (a: T) => void;
26+
>fn3 : Symbol(fn3, Decl(circularReferenceInReturnType.ts, 4, 31))
27+
>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 6, 21))
28+
>T2 : Symbol(T2, Decl(circularReferenceInReturnType.ts, 6, 28))
29+
>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 6, 32))
30+
>arg : Symbol(arg, Decl(circularReferenceInReturnType.ts, 6, 37))
31+
>T2 : Symbol(T2, Decl(circularReferenceInReturnType.ts, 6, 28))
32+
>a : Symbol(a, Decl(circularReferenceInReturnType.ts, 6, 58))
33+
>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 6, 21))
34+
35+
const res3 = fn3()(() => res3);
36+
>res3 : Symbol(res3, Decl(circularReferenceInReturnType.ts, 7, 5))
37+
>fn3 : Symbol(fn3, Decl(circularReferenceInReturnType.ts, 4, 31))
38+
>res3 : Symbol(res3, Decl(circularReferenceInReturnType.ts, 7, 5))
39+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
=== tests/cases/compiler/circularReferenceInReturnType.ts ===
2+
declare function fn1<T>(cb: () => T): string;
3+
>fn1 : <T>(cb: () => T) => string
4+
>cb : () => T
5+
6+
const res1 = fn1(() => res1);
7+
>res1 : string
8+
>fn1(() => res1) : string
9+
>fn1 : <T>(cb: () => T) => string
10+
>() => res1 : () => string
11+
>res1 : string
12+
13+
declare function fn2<T>(): (cb: () => any) => (a: T) => void;
14+
>fn2 : <T>() => (cb: () => any) => (a: T) => void
15+
>cb : () => any
16+
>a : T
17+
18+
const res2 = fn2()(() => res2);
19+
>res2 : (a: unknown) => void
20+
>fn2()(() => res2) : (a: unknown) => void
21+
>fn2() : (cb: () => any) => (a: unknown) => void
22+
>fn2 : <T>() => (cb: () => any) => (a: T) => void
23+
>() => res2 : () => (a: unknown) => void
24+
>res2 : (a: unknown) => void
25+
26+
declare function fn3<T>(): <T2>(cb: (arg: T2) => any) => (a: T) => void;
27+
>fn3 : <T>() => <T2>(cb: (arg: T2) => any) => (a: T) => void
28+
>cb : (arg: T2) => any
29+
>arg : T2
30+
>a : T
31+
32+
const res3 = fn3()(() => res3);
33+
>res3 : (a: unknown) => void
34+
>fn3()(() => res3) : (a: unknown) => void
35+
>fn3() : <T2>(cb: (arg: T2) => any) => (a: unknown) => void
36+
>fn3 : <T>() => <T2>(cb: (arg: T2) => any) => (a: T) => void
37+
>() => res3 : () => (a: unknown) => void
38+
>res3 : (a: unknown) => void
39+
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
=== tests/cases/compiler/circularReferenceInReturnType2.ts ===
2+
type ObjectType<Source> = {
3+
>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0))
4+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 0, 16))
5+
6+
kind: "object";
7+
>kind : Symbol(kind, Decl(circularReferenceInReturnType2.ts, 0, 27))
8+
9+
__source: (source: Source) => void;
10+
>__source : Symbol(__source, Decl(circularReferenceInReturnType2.ts, 1, 17))
11+
>source : Symbol(source, Decl(circularReferenceInReturnType2.ts, 2, 13))
12+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 0, 16))
13+
14+
};
15+
16+
type Field<Source, Key extends string> = {
17+
>Field : Symbol(Field, Decl(circularReferenceInReturnType2.ts, 3, 2))
18+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 5, 11))
19+
>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 5, 18))
20+
21+
__key: (key: Key) => void;
22+
>__key : Symbol(__key, Decl(circularReferenceInReturnType2.ts, 5, 42))
23+
>key : Symbol(key, Decl(circularReferenceInReturnType2.ts, 6, 10))
24+
>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 5, 18))
25+
26+
__source: (source: Source) => void;
27+
>__source : Symbol(__source, Decl(circularReferenceInReturnType2.ts, 6, 28))
28+
>source : Symbol(source, Decl(circularReferenceInReturnType2.ts, 7, 13))
29+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 5, 11))
30+
31+
};
32+
33+
declare const object: <Source>() => <
34+
>object : Symbol(object, Decl(circularReferenceInReturnType2.ts, 10, 13))
35+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 10, 23))
36+
37+
Fields extends {
38+
>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37))
39+
40+
[Key in keyof Fields]: Field<Source, Key & string>;
41+
>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 12, 5))
42+
>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37))
43+
>Field : Symbol(Field, Decl(circularReferenceInReturnType2.ts, 3, 2))
44+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 10, 23))
45+
>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 12, 5))
46+
}
47+
>(config: {
48+
>config : Symbol(config, Decl(circularReferenceInReturnType2.ts, 14, 2))
49+
50+
name: string;
51+
>name : Symbol(name, Decl(circularReferenceInReturnType2.ts, 14, 11))
52+
53+
fields: Fields | (() => Fields);
54+
>fields : Symbol(fields, Decl(circularReferenceInReturnType2.ts, 15, 15))
55+
>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37))
56+
>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37))
57+
58+
}) => ObjectType<Source>;
59+
>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0))
60+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 10, 23))
61+
62+
type InferValueFromObjectType<Type extends ObjectType<any>> =
63+
>InferValueFromObjectType : Symbol(InferValueFromObjectType, Decl(circularReferenceInReturnType2.ts, 17, 25))
64+
>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 19, 30))
65+
>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0))
66+
67+
Type extends ObjectType<infer Source> ? Source : never;
68+
>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 19, 30))
69+
>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0))
70+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 20, 31))
71+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 20, 31))
72+
73+
type FieldResolver<Source, TType extends ObjectType<any>> = (
74+
>FieldResolver : Symbol(FieldResolver, Decl(circularReferenceInReturnType2.ts, 20, 57))
75+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 22, 19))
76+
>TType : Symbol(TType, Decl(circularReferenceInReturnType2.ts, 22, 26))
77+
>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0))
78+
79+
source: Source
80+
>source : Symbol(source, Decl(circularReferenceInReturnType2.ts, 22, 61))
81+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 22, 19))
82+
83+
) => InferValueFromObjectType<TType>;
84+
>InferValueFromObjectType : Symbol(InferValueFromObjectType, Decl(circularReferenceInReturnType2.ts, 17, 25))
85+
>TType : Symbol(TType, Decl(circularReferenceInReturnType2.ts, 22, 26))
86+
87+
type FieldFuncArgs<Source, Type extends ObjectType<any>> = {
88+
>FieldFuncArgs : Symbol(FieldFuncArgs, Decl(circularReferenceInReturnType2.ts, 24, 37))
89+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 26, 19))
90+
>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 26, 26))
91+
>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0))
92+
93+
type: Type;
94+
>type : Symbol(type, Decl(circularReferenceInReturnType2.ts, 26, 60))
95+
>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 26, 26))
96+
97+
resolve: FieldResolver<Source, Type>;
98+
>resolve : Symbol(resolve, Decl(circularReferenceInReturnType2.ts, 27, 13))
99+
>FieldResolver : Symbol(FieldResolver, Decl(circularReferenceInReturnType2.ts, 20, 57))
100+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 26, 19))
101+
>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 26, 26))
102+
103+
};
104+
105+
declare const field: <Source, Type extends ObjectType<any>, Key extends string>(
106+
>field : Symbol(field, Decl(circularReferenceInReturnType2.ts, 31, 13))
107+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 31, 22))
108+
>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 31, 29))
109+
>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0))
110+
>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 31, 59))
111+
112+
field: FieldFuncArgs<Source, Type>
113+
>field : Symbol(field, Decl(circularReferenceInReturnType2.ts, 31, 80))
114+
>FieldFuncArgs : Symbol(FieldFuncArgs, Decl(circularReferenceInReturnType2.ts, 24, 37))
115+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 31, 22))
116+
>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 31, 29))
117+
118+
) => Field<Source, Key>;
119+
>Field : Symbol(Field, Decl(circularReferenceInReturnType2.ts, 3, 2))
120+
>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 31, 22))
121+
>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 31, 59))
122+
123+
type Something = { foo: number };
124+
>Something : Symbol(Something, Decl(circularReferenceInReturnType2.ts, 33, 24))
125+
>foo : Symbol(foo, Decl(circularReferenceInReturnType2.ts, 35, 18))
126+
127+
const A = object<Something>()({
128+
>A : Symbol(A, Decl(circularReferenceInReturnType2.ts, 37, 5))
129+
>object : Symbol(object, Decl(circularReferenceInReturnType2.ts, 10, 13))
130+
>Something : Symbol(Something, Decl(circularReferenceInReturnType2.ts, 33, 24))
131+
132+
name: "A",
133+
>name : Symbol(name, Decl(circularReferenceInReturnType2.ts, 37, 31))
134+
135+
fields: () => ({
136+
>fields : Symbol(fields, Decl(circularReferenceInReturnType2.ts, 38, 12))
137+
138+
a: field({
139+
>a : Symbol(a, Decl(circularReferenceInReturnType2.ts, 39, 18))
140+
>field : Symbol(field, Decl(circularReferenceInReturnType2.ts, 31, 13))
141+
142+
type: A,
143+
>type : Symbol(type, Decl(circularReferenceInReturnType2.ts, 40, 14))
144+
>A : Symbol(A, Decl(circularReferenceInReturnType2.ts, 37, 5))
145+
146+
resolve() {
147+
>resolve : Symbol(resolve, Decl(circularReferenceInReturnType2.ts, 41, 14))
148+
149+
return {
150+
foo: 100,
151+
>foo : Symbol(foo, Decl(circularReferenceInReturnType2.ts, 43, 16))
152+
153+
};
154+
},
155+
}),
156+
}),
157+
});
158+

0 commit comments

Comments
 (0)