Skip to content

Commit 9ddbb85

Browse files
Copilotjakebailey
andcommitted
Allow implicit undefined returns when the contextual union type contains it
Port of TypeScript PR #57912. Changed the checker to use someType() instead of a direct flag check when determining if an implicit return should produce undefined vs void. This allows functions with a contextual return type that is a union containing undefined to have implicit undefined returns. Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
1 parent 0387078 commit 9ddbb85

11 files changed

+24
-171
lines changed

internal/checker/checker.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19700,7 +19700,7 @@ func (c *Checker) getReturnTypeFromBody(fn *ast.Node, checkMode CheckMode) *Type
1970019700
// For an async function, the return type will not be void/undefined, but rather a Promise for void/undefined.
1970119701
contextualReturnType := c.getContextualReturnType(fn, ContextFlagsNone)
1970219702
var returnType *Type
19703-
if contextualReturnType != nil && core.OrElse(c.unwrapReturnType(contextualReturnType, functionFlags), c.voidType).flags&TypeFlagsUndefined != 0 {
19703+
if contextualReturnType != nil && someType(core.OrElse(c.unwrapReturnType(contextualReturnType, functionFlags), c.voidType), func(t *Type) bool { return t.flags&TypeFlagsUndefined != 0 }) {
1970419704
returnType = c.undefinedType
1970519705
} else {
1970619706
returnType = c.voidType

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressions(target=es2015).errors.txt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,12 @@ functionsMissingReturnStatementsAndExpressions.ts(45,5): error TS2322: Type 'nul
55
functionsMissingReturnStatementsAndExpressions.ts(74,5): error TS2322: Type 'undefined' is not assignable to type 'number'.
66
functionsMissingReturnStatementsAndExpressions.ts(99,17): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
77
functionsMissingReturnStatementsAndExpressions.ts(107,17): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
8-
functionsMissingReturnStatementsAndExpressions.ts(120,7): error TS2322: Type '() => void' is not assignable to type '() => number | undefined'.
9-
Type 'void' is not assignable to type 'number | undefined'.
10-
functionsMissingReturnStatementsAndExpressions.ts(124,7): error TS2322: Type '() => void' is not assignable to type '() => number | undefined'.
11-
Type 'void' is not assignable to type 'number | undefined'.
128
functionsMissingReturnStatementsAndExpressions.ts(130,16): error TS2378: A 'get' accessor must return a value.
139
functionsMissingReturnStatementsAndExpressions.ts(152,15): error TS18050: The value 'undefined' cannot be used here.
1410
functionsMissingReturnStatementsAndExpressions.ts(153,5): error TS1003: Identifier expected.
1511

1612

17-
==== functionsMissingReturnStatementsAndExpressions.ts (12 errors) ====
13+
==== functionsMissingReturnStatementsAndExpressions.ts (10 errors) ====
1814
function f1(): string {
1915
~~~~~~
2016
!!! error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
@@ -149,16 +145,10 @@ functionsMissingReturnStatementsAndExpressions.ts(153,5): error TS1003: Identifi
149145
}
150146

151147
const f32: () => undefined | number = () => {
152-
~~~
153-
!!! error TS2322: Type '() => void' is not assignable to type '() => number | undefined'.
154-
!!! error TS2322: Type 'void' is not assignable to type 'number | undefined'.
155148
// Error, contextual type for implicit return isn't just `undefined`
156149
}
157150

158151
const f33: () => undefined | number = () => {
159-
~~~
160-
!!! error TS2322: Type '() => void' is not assignable to type '() => number | undefined'.
161-
!!! error TS2322: Type 'void' is not assignable to type 'number | undefined'.
162152
// Error, contextual type for expression-less return isn't just `undefined`
163153
return;
164154
}

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressions(target=es2015).errors.txt.diff

Lines changed: 0 additions & 37 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressions(target=es2015).types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,14 @@ const f31: () => undefined = () => {
185185

186186
const f32: () => undefined | number = () => {
187187
>f32 : () => number | undefined
188-
>() => { // Error, contextual type for implicit return isn't just `undefined`} : () => void
188+
>() => { // Error, contextual type for implicit return isn't just `undefined`} : () => undefined
189189

190190
// Error, contextual type for implicit return isn't just `undefined`
191191
}
192192

193193
const f33: () => undefined | number = () => {
194194
>f33 : () => number | undefined
195-
>() => { // Error, contextual type for expression-less return isn't just `undefined` return;} : () => void
195+
>() => { // Error, contextual type for expression-less return isn't just `undefined` return;} : () => undefined
196196

197197
// Error, contextual type for expression-less return isn't just `undefined`
198198
return;

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressions(target=es2015).types.diff

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,15 @@
3030

3131
const f32: () => undefined | number = () => {
3232
->f32 : () => undefined | number
33-
->() => { // Error, contextual type for implicit return isn't just `undefined`} : () => undefined
3433
+>f32 : () => number | undefined
35-
+>() => { // Error, contextual type for implicit return isn't just `undefined`} : () => void
34+
>() => { // Error, contextual type for implicit return isn't just `undefined`} : () => undefined
3635

3736
// Error, contextual type for implicit return isn't just `undefined`
3837
}
3938

4039
const f33: () => undefined | number = () => {
4140
->f33 : () => undefined | number
42-
->() => { // Error, contextual type for expression-less return isn't just `undefined` return;} : () => undefined
4341
+>f33 : () => number | undefined
44-
+>() => { // Error, contextual type for expression-less return isn't just `undefined` return;} : () => void
42+
>() => { // Error, contextual type for expression-less return isn't just `undefined` return;} : () => undefined
4543

46-
// Error, contextual type for expression-less return isn't just `undefined`
47-
return;
44+
// Error, contextual type for expression-less return isn't just `undefined`

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.errors.txt

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(5,17): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
22
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(9,17): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
3-
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(17,7): error TS2322: Type '() => void' is not assignable to type '() => number | undefined'.
4-
Type 'void' is not assignable to type 'number | undefined'.
53
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(21,7): error TS2322: Type '() => void' is not assignable to type '() => number'.
64
Type 'void' is not assignable to type 'number'.
75
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(29,23): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
86
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(33,23): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
97
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(52,3): error TS2345: Argument of type '() => void' is not assignable to parameter of type '() => undefined'.
108
Type 'void' is not assignable to type 'undefined'.
11-
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(63,7): error TS2322: Type '() => void' is not assignable to type 'FN'.
12-
Type 'void' is not assignable to type 'Promise<undefined> | undefined'.
13-
functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(71,7): error TS2322: Type '() => void' is not assignable to type 'FN'.
14-
Type 'void' is not assignable to type 'Promise<undefined> | undefined'.
159

1610

17-
==== functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts (9 errors) ====
11+
==== functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts (6 errors) ====
1812
function f10(): undefined {
1913
// Ok, return type allows implicit return of undefined
2014
}
@@ -36,9 +30,6 @@ functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(71,7): error T
3630
}
3731

3832
const f21: () => undefined | number = () => {
39-
~~~
40-
!!! error TS2322: Type '() => void' is not assignable to type '() => number | undefined'.
41-
!!! error TS2322: Type 'void' is not assignable to type 'number | undefined'.
4233
// Ok, contextual type for implicit return contains undefined
4334
}
4435

@@ -95,9 +86,6 @@ functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(71,7): error T
9586
type FN = () => Promise<undefined> | undefined;
9687

9788
const fn1: FN = () => {
98-
~~~
99-
!!! error TS2322: Type '() => void' is not assignable to type 'FN'.
100-
!!! error TS2322: Type 'void' is not assignable to type 'Promise<undefined> | undefined'.
10189
return;
10290
};
10391

@@ -106,9 +94,6 @@ functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(71,7): error T
10694
};
10795

10896
const fn3: FN = () => {};
109-
~~~
110-
!!! error TS2322: Type '() => void' is not assignable to type 'FN'.
111-
!!! error TS2322: Type 'void' is not assignable to type 'Promise<undefined> | undefined'.
11297

11398
const fn4: FN = async () => {};
11499

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.errors.txt.diff

Lines changed: 0 additions & 56 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const f20: () => undefined = () => {
2828

2929
const f21: () => undefined | number = () => {
3030
>f21 : () => number | undefined
31-
>() => { // Ok, contextual type for implicit return contains undefined} : () => void
31+
>() => { // Ok, contextual type for implicit return contains undefined} : () => undefined
3232

3333
// Ok, contextual type for implicit return contains undefined
3434
}
@@ -107,7 +107,7 @@ type FN = () => Promise<undefined> | undefined;
107107

108108
const fn1: FN = () => {
109109
>fn1 : FN
110-
>() => { return;} : () => void
110+
>() => { return;} : () => undefined
111111

112112
return;
113113
};
@@ -121,7 +121,7 @@ const fn2: FN = async () => {
121121

122122
const fn3: FN = () => {};
123123
>fn3 : FN
124-
>() => {} : () => void
124+
>() => {} : () => undefined
125125

126126
const fn4: FN = async () => {};
127127
>fn4 : FN

testdata/baselines/reference/submodule/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.types.diff

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@
1414

1515
const f21: () => undefined | number = () => {
1616
->f21 : () => undefined | number
17-
->() => { // Ok, contextual type for implicit return contains undefined} : () => undefined
1817
+>f21 : () => number | undefined
19-
+>() => { // Ok, contextual type for implicit return contains undefined} : () => void
18+
>() => { // Ok, contextual type for implicit return contains undefined} : () => undefined
2019

2120
// Ok, contextual type for implicit return contains undefined
22-
}
2321
@@= skipped -20, +20 lines =@@
2422
}
2523

@@ -28,22 +26,4 @@
2826
+>f31 : () => Promise<number | undefined>
2927

3028
// Error, return type isn't just undefined
31-
}
32-
@@= skipped -60, +60 lines =@@
33-
34-
const fn1: FN = () => {
35-
>fn1 : FN
36-
->() => { return;} : () => undefined
37-
+>() => { return;} : () => void
38-
39-
return;
40-
};
41-
@@= skipped -14, +14 lines =@@
42-
43-
const fn3: FN = () => {};
44-
>fn3 : FN
45-
->() => {} : () => undefined
46-
+>() => {} : () => void
47-
48-
const fn4: FN = async () => {};
49-
>fn4 : FN
29+
}

testdata/baselines/reference/submodule/compiler/inferenceDoesNotAddUndefinedOrNull.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ function flatMapChildren<T>(node: Node, cb: (child: Node) => readonly T[] | T |
3131
>[] : never[]
3232

3333
node.forEachChild(child => {
34-
>node.forEachChild(child => { const value = cb(child); if (value !== undefined) { result.push(...toArray(value)); } }) : void | undefined
34+
>node.forEachChild(child => { const value = cb(child); if (value !== undefined) { result.push(...toArray(value)); } }) : undefined
3535
>node.forEachChild : <T_1>(cbNode: (node: Node) => T_1 | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T_1 | undefined) | undefined) => T_1 | undefined
3636
>node : Node
3737
>forEachChild : <T_1>(cbNode: (node: Node) => T_1 | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T_1 | undefined) | undefined) => T_1 | undefined
38-
>child => { const value = cb(child); if (value !== undefined) { result.push(...toArray(value)); } } : (child: Node) => void
38+
>child => { const value = cb(child); if (value !== undefined) { result.push(...toArray(value)); } } : (child: Node) => undefined
3939
>child : Node
4040

4141
const value = cb(child);
@@ -75,11 +75,11 @@ function flatMapChildren2<T>(node: Node, cb: (child: Node) => readonly T[] | T |
7575
>[] : never[]
7676

7777
node.forEachChild(child => {
78-
>node.forEachChild(child => { const value = cb(child); if (value !== null) { result.push(...toArray(value)); } }) : void | undefined
78+
>node.forEachChild(child => { const value = cb(child); if (value !== null) { result.push(...toArray(value)); } }) : undefined
7979
>node.forEachChild : <T_1>(cbNode: (node: Node) => T_1 | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T_1 | undefined) | undefined) => T_1 | undefined
8080
>node : Node
8181
>forEachChild : <T_1>(cbNode: (node: Node) => T_1 | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T_1 | undefined) | undefined) => T_1 | undefined
82-
>child => { const value = cb(child); if (value !== null) { result.push(...toArray(value)); } } : (child: Node) => void
82+
>child => { const value = cb(child); if (value !== null) { result.push(...toArray(value)); } } : (child: Node) => undefined
8383
>child : Node
8484

8585
const value = cb(child);

0 commit comments

Comments
 (0)