Skip to content

Commit 718d798

Browse files
authored
Do not infer yield* type from contextual TReturn (#58621)
1 parent 2a9e4b8 commit 718d798

File tree

7 files changed

+331
-6
lines changed

7 files changed

+331
-6
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30915,9 +30915,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3091530915
if (!node.asteriskToken && contextualReturnType.flags & TypeFlags.Union) {
3091630916
contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator));
3091730917
}
30918-
return node.asteriskToken
30919-
? contextualReturnType
30920-
: getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, isAsyncGenerator);
30918+
if (node.asteriskToken) {
30919+
const iterationTypes = getIterationTypesOfGeneratorFunctionReturnType(contextualReturnType, isAsyncGenerator);
30920+
const yieldType = iterationTypes?.yieldType ?? silentNeverType;
30921+
const returnType = getContextualType(node, contextFlags) ?? silentNeverType;
30922+
const nextType = iterationTypes?.nextType ?? unknownType;
30923+
const generatorType = createGeneratorType(yieldType, returnType, nextType, /*isAsyncGenerator*/ false);
30924+
if (isAsyncGenerator) {
30925+
const asyncGeneratorType = createGeneratorType(yieldType, returnType, nextType, /*isAsyncGenerator*/ true);
30926+
return getUnionType([generatorType, asyncGeneratorType]);
30927+
}
30928+
return generatorType;
30929+
}
30930+
return getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, isAsyncGenerator);
3092130931
}
3092230932
}
3092330933

@@ -37829,7 +37839,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3782937839
}
3783037840

3783137841
if (isGenerator) {
37832-
return createGeneratorReturnType(
37842+
return createGeneratorType(
3783337843
yieldType || neverType,
3783437844
returnType || fallbackReturnType,
3783537845
nextType || getContextualIterationType(IterationTypeKind.Next, func) || unknownType,
@@ -37846,7 +37856,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3784637856
}
3784737857
}
3784837858

37849-
function createGeneratorReturnType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) {
37859+
function createGeneratorType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) {
3785037860
const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver;
3785137861
const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false);
3785237862
yieldType = resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || unknownType;
@@ -40648,7 +40658,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4064840658
const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType;
4064940659
const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, (functionFlags & FunctionFlags.Async) !== 0) || generatorYieldType;
4065040660
const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, (functionFlags & FunctionFlags.Async) !== 0) || unknownType;
40651-
const generatorInstantiation = createGeneratorReturnType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async));
40661+
const generatorInstantiation = createGeneratorType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async));
4065240662

4065340663
return checkTypeAssignableTo(generatorInstantiation, returnType, errorNode);
4065440664
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//// [tests/cases/compiler/asyncYieldStarContextualType.ts] ////
2+
3+
=== asyncYieldStarContextualType.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57903
5+
interface Result<T, E> {
6+
>Result : Symbol(Result, Decl(asyncYieldStarContextualType.ts, 0, 0))
7+
>T : Symbol(T, Decl(asyncYieldStarContextualType.ts, 1, 17))
8+
>E : Symbol(E, Decl(asyncYieldStarContextualType.ts, 1, 19))
9+
10+
[Symbol.iterator](): Generator<E, T, unknown>
11+
>[Symbol.iterator] : Symbol(Result[Symbol.iterator], Decl(asyncYieldStarContextualType.ts, 1, 24))
12+
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
13+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
14+
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
15+
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
16+
>E : Symbol(E, Decl(asyncYieldStarContextualType.ts, 1, 19))
17+
>T : Symbol(T, Decl(asyncYieldStarContextualType.ts, 1, 17))
18+
}
19+
20+
type Book = { id: string; title: string; authorId: string };
21+
>Book : Symbol(Book, Decl(asyncYieldStarContextualType.ts, 3, 1))
22+
>id : Symbol(id, Decl(asyncYieldStarContextualType.ts, 5, 13))
23+
>title : Symbol(title, Decl(asyncYieldStarContextualType.ts, 5, 25))
24+
>authorId : Symbol(authorId, Decl(asyncYieldStarContextualType.ts, 5, 40))
25+
26+
type Author = { id: string; name: string };
27+
>Author : Symbol(Author, Decl(asyncYieldStarContextualType.ts, 5, 60))
28+
>id : Symbol(id, Decl(asyncYieldStarContextualType.ts, 6, 15))
29+
>name : Symbol(name, Decl(asyncYieldStarContextualType.ts, 6, 27))
30+
31+
type BookWithAuthor = Book & { author: Author };
32+
>BookWithAuthor : Symbol(BookWithAuthor, Decl(asyncYieldStarContextualType.ts, 6, 43))
33+
>Book : Symbol(Book, Decl(asyncYieldStarContextualType.ts, 3, 1))
34+
>author : Symbol(author, Decl(asyncYieldStarContextualType.ts, 7, 30))
35+
>Author : Symbol(Author, Decl(asyncYieldStarContextualType.ts, 5, 60))
36+
37+
declare const authorPromise: Promise<Result<Author, "NOT_FOUND_AUTHOR">>;
38+
>authorPromise : Symbol(authorPromise, Decl(asyncYieldStarContextualType.ts, 9, 13))
39+
>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, --, --))
40+
>Result : Symbol(Result, Decl(asyncYieldStarContextualType.ts, 0, 0))
41+
>Author : Symbol(Author, Decl(asyncYieldStarContextualType.ts, 5, 60))
42+
43+
declare const mapper: <T>(result: Result<T, "NOT_FOUND_AUTHOR">) => Result<T, "NOT_FOUND_AUTHOR">;
44+
>mapper : Symbol(mapper, Decl(asyncYieldStarContextualType.ts, 10, 13))
45+
>T : Symbol(T, Decl(asyncYieldStarContextualType.ts, 10, 23))
46+
>result : Symbol(result, Decl(asyncYieldStarContextualType.ts, 10, 26))
47+
>Result : Symbol(Result, Decl(asyncYieldStarContextualType.ts, 0, 0))
48+
>T : Symbol(T, Decl(asyncYieldStarContextualType.ts, 10, 23))
49+
>Result : Symbol(Result, Decl(asyncYieldStarContextualType.ts, 0, 0))
50+
>T : Symbol(T, Decl(asyncYieldStarContextualType.ts, 10, 23))
51+
52+
declare const g: <T, U, V>() => AsyncGenerator<T, U, V>;
53+
>g : Symbol(g, Decl(asyncYieldStarContextualType.ts, 11, 13))
54+
>T : Symbol(T, Decl(asyncYieldStarContextualType.ts, 11, 18))
55+
>U : Symbol(U, Decl(asyncYieldStarContextualType.ts, 11, 20))
56+
>V : Symbol(V, Decl(asyncYieldStarContextualType.ts, 11, 23))
57+
>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --))
58+
>T : Symbol(T, Decl(asyncYieldStarContextualType.ts, 11, 18))
59+
>U : Symbol(U, Decl(asyncYieldStarContextualType.ts, 11, 20))
60+
>V : Symbol(V, Decl(asyncYieldStarContextualType.ts, 11, 23))
61+
62+
async function* f(): AsyncGenerator<"NOT_FOUND_AUTHOR" | "NOT_FOUND_BOOK", BookWithAuthor, unknown> {
63+
>f : Symbol(f, Decl(asyncYieldStarContextualType.ts, 11, 56))
64+
>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --))
65+
>BookWithAuthor : Symbol(BookWithAuthor, Decl(asyncYieldStarContextualType.ts, 6, 43))
66+
67+
// Without yield*, the type of test1 is
68+
// Result<Author, "NOT_FOUND_AUTHOR>
69+
const test1 = await authorPromise.then(mapper)
70+
>test1 : Symbol(test1, Decl(asyncYieldStarContextualType.ts, 16, 9))
71+
>authorPromise.then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
72+
>authorPromise : Symbol(authorPromise, Decl(asyncYieldStarContextualType.ts, 9, 13))
73+
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
74+
>mapper : Symbol(mapper, Decl(asyncYieldStarContextualType.ts, 10, 13))
75+
76+
// With yield*, the type of test2 is
77+
// Author | BookWithAuthor
78+
// But this codepath has no way to produce BookWithAuthor
79+
const test2 = yield* await authorPromise.then(mapper)
80+
>test2 : Symbol(test2, Decl(asyncYieldStarContextualType.ts, 21, 9))
81+
>authorPromise.then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
82+
>authorPromise : Symbol(authorPromise, Decl(asyncYieldStarContextualType.ts, 9, 13))
83+
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
84+
>mapper : Symbol(mapper, Decl(asyncYieldStarContextualType.ts, 10, 13))
85+
86+
const x1 = yield* g();
87+
>x1 : Symbol(x1, Decl(asyncYieldStarContextualType.ts, 23, 9))
88+
>g : Symbol(g, Decl(asyncYieldStarContextualType.ts, 11, 13))
89+
90+
const x2: number = yield* g();
91+
>x2 : Symbol(x2, Decl(asyncYieldStarContextualType.ts, 24, 9))
92+
>g : Symbol(g, Decl(asyncYieldStarContextualType.ts, 11, 13))
93+
94+
return null! as BookWithAuthor;
95+
>BookWithAuthor : Symbol(BookWithAuthor, Decl(asyncYieldStarContextualType.ts, 6, 43))
96+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//// [tests/cases/compiler/asyncYieldStarContextualType.ts] ////
2+
3+
=== asyncYieldStarContextualType.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57903
5+
interface Result<T, E> {
6+
[Symbol.iterator](): Generator<E, T, unknown>
7+
>[Symbol.iterator] : () => Generator<E, T, unknown>
8+
> : ^^^^^^
9+
>Symbol.iterator : unique symbol
10+
> : ^^^^^^^^^^^^^
11+
>Symbol : SymbolConstructor
12+
> : ^^^^^^^^^^^^^^^^^
13+
>iterator : unique symbol
14+
> : ^^^^^^^^^^^^^
15+
}
16+
17+
type Book = { id: string; title: string; authorId: string };
18+
>Book : Book
19+
> : ^^^^
20+
>id : string
21+
> : ^^^^^^
22+
>title : string
23+
> : ^^^^^^
24+
>authorId : string
25+
> : ^^^^^^
26+
27+
type Author = { id: string; name: string };
28+
>Author : Author
29+
> : ^^^^^^
30+
>id : string
31+
> : ^^^^^^
32+
>name : string
33+
> : ^^^^^^
34+
35+
type BookWithAuthor = Book & { author: Author };
36+
>BookWithAuthor : BookWithAuthor
37+
> : ^^^^^^^^^^^^^^
38+
>author : Author
39+
> : ^^^^^^
40+
41+
declare const authorPromise: Promise<Result<Author, "NOT_FOUND_AUTHOR">>;
42+
>authorPromise : Promise<Result<Author, "NOT_FOUND_AUTHOR">>
43+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44+
45+
declare const mapper: <T>(result: Result<T, "NOT_FOUND_AUTHOR">) => Result<T, "NOT_FOUND_AUTHOR">;
46+
>mapper : <T>(result: Result<T, "NOT_FOUND_AUTHOR">) => Result<T, "NOT_FOUND_AUTHOR">
47+
> : ^ ^^ ^^ ^^^^^
48+
>result : Result<T, "NOT_FOUND_AUTHOR">
49+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
51+
declare const g: <T, U, V>() => AsyncGenerator<T, U, V>;
52+
>g : <T, U, V>() => AsyncGenerator<T, U, V>
53+
> : ^ ^^ ^^ ^^^^^^^
54+
55+
async function* f(): AsyncGenerator<"NOT_FOUND_AUTHOR" | "NOT_FOUND_BOOK", BookWithAuthor, unknown> {
56+
>f : () => AsyncGenerator<"NOT_FOUND_AUTHOR" | "NOT_FOUND_BOOK", BookWithAuthor, unknown>
57+
> : ^^^^^^
58+
59+
// Without yield*, the type of test1 is
60+
// Result<Author, "NOT_FOUND_AUTHOR>
61+
const test1 = await authorPromise.then(mapper)
62+
>test1 : Result<Author, "NOT_FOUND_AUTHOR">
63+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
64+
>await authorPromise.then(mapper) : Result<Author, "NOT_FOUND_AUTHOR">
65+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66+
>authorPromise.then(mapper) : Promise<Result<Author, "NOT_FOUND_AUTHOR">>
67+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68+
>authorPromise.then : <TResult1 = Result<Author, "NOT_FOUND_AUTHOR">, TResult2 = never>(onfulfilled?: (value: Result<Author, "NOT_FOUND_AUTHOR">) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
69+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70+
>authorPromise : Promise<Result<Author, "NOT_FOUND_AUTHOR">>
71+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
72+
>then : <TResult1 = Result<Author, "NOT_FOUND_AUTHOR">, TResult2 = never>(onfulfilled?: (value: Result<Author, "NOT_FOUND_AUTHOR">) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
73+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
74+
>mapper : <T>(result: Result<T, "NOT_FOUND_AUTHOR">) => Result<T, "NOT_FOUND_AUTHOR">
75+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76+
77+
// With yield*, the type of test2 is
78+
// Author | BookWithAuthor
79+
// But this codepath has no way to produce BookWithAuthor
80+
const test2 = yield* await authorPromise.then(mapper)
81+
>test2 : Author
82+
> : ^^^^^^
83+
>yield* await authorPromise.then(mapper) : Author
84+
> : ^^^^^^
85+
>await authorPromise.then(mapper) : Result<Author, "NOT_FOUND_AUTHOR">
86+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
87+
>authorPromise.then(mapper) : Promise<Result<Author, "NOT_FOUND_AUTHOR">>
88+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89+
>authorPromise.then : <TResult1 = Result<Author, "NOT_FOUND_AUTHOR">, TResult2 = never>(onfulfilled?: (value: Result<Author, "NOT_FOUND_AUTHOR">) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
90+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91+
>authorPromise : Promise<Result<Author, "NOT_FOUND_AUTHOR">>
92+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
93+
>then : <TResult1 = Result<Author, "NOT_FOUND_AUTHOR">, TResult2 = never>(onfulfilled?: (value: Result<Author, "NOT_FOUND_AUTHOR">) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
94+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
95+
>mapper : <T>(result: Result<T, "NOT_FOUND_AUTHOR">) => Result<T, "NOT_FOUND_AUTHOR">
96+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
97+
98+
const x1 = yield* g();
99+
>x1 : unknown
100+
> : ^^^^^^^
101+
>yield* g() : unknown
102+
> : ^^^^^^^
103+
>g() : AsyncGenerator<"NOT_FOUND_AUTHOR" | "NOT_FOUND_BOOK", unknown, unknown>
104+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
105+
>g : <T, U, V>() => AsyncGenerator<T, U, V>
106+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107+
108+
const x2: number = yield* g();
109+
>x2 : number
110+
> : ^^^^^^
111+
>yield* g() : number
112+
> : ^^^^^^
113+
>g() : AsyncGenerator<"NOT_FOUND_AUTHOR" | "NOT_FOUND_BOOK", number, unknown>
114+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
115+
>g : <T, U, V>() => AsyncGenerator<T, U, V>
116+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
117+
118+
return null! as BookWithAuthor;
119+
>null! as BookWithAuthor : BookWithAuthor
120+
> : ^^^^^^^^^^^^^^
121+
>null! : null
122+
> : ^^^^
123+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [tests/cases/compiler/yieldStarContextualType.ts] ////
2+
3+
=== yieldStarContextualType.ts ===
4+
declare const g: <T, U, V>() => Generator<T, U, V>;
5+
>g : Symbol(g, Decl(yieldStarContextualType.ts, 0, 13))
6+
>T : Symbol(T, Decl(yieldStarContextualType.ts, 0, 18))
7+
>U : Symbol(U, Decl(yieldStarContextualType.ts, 0, 20))
8+
>V : Symbol(V, Decl(yieldStarContextualType.ts, 0, 23))
9+
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
10+
>T : Symbol(T, Decl(yieldStarContextualType.ts, 0, 18))
11+
>U : Symbol(U, Decl(yieldStarContextualType.ts, 0, 20))
12+
>V : Symbol(V, Decl(yieldStarContextualType.ts, 0, 23))
13+
14+
function* f(): Generator<string, void, unknown> {
15+
>f : Symbol(f, Decl(yieldStarContextualType.ts, 0, 51))
16+
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
17+
18+
const x1 = yield* g();
19+
>x1 : Symbol(x1, Decl(yieldStarContextualType.ts, 3, 9))
20+
>g : Symbol(g, Decl(yieldStarContextualType.ts, 0, 13))
21+
22+
const x2: number = yield* g();
23+
>x2 : Symbol(x2, Decl(yieldStarContextualType.ts, 4, 9))
24+
>g : Symbol(g, Decl(yieldStarContextualType.ts, 0, 13))
25+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [tests/cases/compiler/yieldStarContextualType.ts] ////
2+
3+
=== yieldStarContextualType.ts ===
4+
declare const g: <T, U, V>() => Generator<T, U, V>;
5+
>g : <T, U, V>() => Generator<T, U, V>
6+
> : ^ ^^ ^^ ^^^^^^^
7+
8+
function* f(): Generator<string, void, unknown> {
9+
>f : () => Generator<string, void, unknown>
10+
> : ^^^^^^
11+
12+
const x1 = yield* g();
13+
>x1 : unknown
14+
> : ^^^^^^^
15+
>yield* g() : unknown
16+
> : ^^^^^^^
17+
>g() : Generator<string, unknown, unknown>
18+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19+
>g : <T, U, V>() => Generator<T, U, V>
20+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21+
22+
const x2: number = yield* g();
23+
>x2 : number
24+
> : ^^^^^^
25+
>yield* g() : number
26+
> : ^^^^^^
27+
>g() : Generator<string, number, unknown>
28+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29+
>g : <T, U, V>() => Generator<T, U, V>
30+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// @target: esnext
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/57903
5+
interface Result<T, E> {
6+
[Symbol.iterator](): Generator<E, T, unknown>
7+
}
8+
9+
type Book = { id: string; title: string; authorId: string };
10+
type Author = { id: string; name: string };
11+
type BookWithAuthor = Book & { author: Author };
12+
13+
declare const authorPromise: Promise<Result<Author, "NOT_FOUND_AUTHOR">>;
14+
declare const mapper: <T>(result: Result<T, "NOT_FOUND_AUTHOR">) => Result<T, "NOT_FOUND_AUTHOR">;
15+
declare const g: <T, U, V>() => AsyncGenerator<T, U, V>;
16+
17+
async function* f(): AsyncGenerator<"NOT_FOUND_AUTHOR" | "NOT_FOUND_BOOK", BookWithAuthor, unknown> {
18+
// Without yield*, the type of test1 is
19+
// Result<Author, "NOT_FOUND_AUTHOR>
20+
const test1 = await authorPromise.then(mapper)
21+
22+
// With yield*, the type of test2 is
23+
// Author | BookWithAuthor
24+
// But this codepath has no way to produce BookWithAuthor
25+
const test2 = yield* await authorPromise.then(mapper)
26+
27+
const x1 = yield* g();
28+
const x2: number = yield* g();
29+
30+
return null! as BookWithAuthor;
31+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @target: esnext
2+
// @noEmit: true
3+
4+
declare const g: <T, U, V>() => Generator<T, U, V>;
5+
6+
function* f(): Generator<string, void, unknown> {
7+
const x1 = yield* g();
8+
const x2: number = yield* g();
9+
}

0 commit comments

Comments
 (0)