Skip to content

Allow implicit undefined returns when the contextual union type contains it - #57912

Merged
Jake Bailey (jakebailey) merged 3 commits into
microsoft:mainfrom
Andarist:implicit-undefined-return-contextual-union
Oct 30, 2025
Merged

Allow implicit undefined returns when the contextual union type contains it#57912
Jake Bailey (jakebailey) merged 3 commits into
microsoft:mainfrom
Andarist:implicit-undefined-return-contextual-union

Conversation

@Andarist

Copy link
Copy Markdown
Contributor

fixes#57840

Ryan Cavanaugh (@RyanCavanaugh) triaged this as a bug here. I'm pretty sure that Anders Hejlsberg (@ahejlsberg) didn't want this to work this way though (as per the description of #53607 and the comment in tests that I had to touch here).

@typescript-botTypeScript Bot (typescript-bot) added the For Backlog Bug PRs that fix a backlog bug label Mar 22, 2024
@jakebailey

Copy link
Copy Markdown
Member

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 22, 2024

Copy link
Copy Markdown
Contributor

Starting jobs; this comment will be updated as builds start and complete.

CommandStatusResults
test top400✅ Started✅ Results
user test this✅ Started✅ Results
run dt✅ Started👀 Results
perf test this faster✅ Started👀 Results
pack this✅ Started✅ Results

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 22, 2024

Copy link
Copy Markdown
Contributor

Hey Jake Bailey (@jakebailey), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/160694/artifacts?artifactName=tgz&fileId=976D886DEE8ACEEF241EF5A35B6FFC03FD3FAC6E83579B8581E469403D8E9E5002&fileName=/typescript-5.5.0-insiders.20240322.tgz"
}
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/pr-build@5.5.0-pr-57912-2".;

@typescript-bot

Copy link
Copy Markdown
Contributor

Hey Jake Bailey (@jakebailey), the results of running the DT tests are ready.

There were interesting changes:

Branch only errors:

Package: nodes7
Error:

Error: /mnt/vss/_work/1/DefinitelyTyped/types/nodes7/nodes7-tests.ts
62:1 error TypeScript@local compile error: Unused '@ts-expect-error' directive @definitelytyped/expect
✖ 1 problem (1 error, 0 warnings)
at combineErrorsAndWarnings (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@definitelytyped+dtslint@0.2.18_typescript@5.5.0-dev.20240322/node_modules/@definitelytyped/dtslint/dist/index.js:194:28)
at runTests (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@definitelytyped+dtslint@0.2.18_typescript@5.5.0-dev.20240322/node_modules/@definitelytyped/dtslint/dist/index.js:186:20)

You can check the log here.

@typescript-bot

Copy link
Copy Markdown
Contributor

Jake Bailey (@jakebailey) Here are the results of running the user tests comparing main and refs/pull/57912/merge:

Everything looks good!

@typescript-bot

Copy link
Copy Markdown
Contributor

Jake Bailey (@jakebailey)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Angular - node (v18.15.0, x64)
Memory used295,514k (± 0.01%)295,515k (± 0.00%)~295,503k295,530kp=0.199 n=6
Parse Time2.66s (± 0.61%)2.67s (± 0.39%)~2.65s2.68sp=0.358 n=6
Bind Time0.83s (± 0.66%)0.83s (± 1.41%)~0.82s0.85sp=0.859 n=6
Check Time8.19s (± 0.23%)8.21s (± 0.31%)~8.18s8.25sp=0.226 n=6
Emit Time7.05s (± 0.20%)7.06s (± 0.45%)~7.03s7.12sp=1.000 n=6
Total Time18.73s (± 0.14%)18.76s (± 0.27%)~18.72s18.85sp=0.198 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used193,094k (± 0.94%)193,656k (± 1.01%)~191,845k195,576kp=0.810 n=6
Parse Time1.35s (± 2.64%)1.36s (± 1.30%)~1.33s1.38sp=0.870 n=6
Bind Time0.72s (± 0.00%)0.72s (± 0.00%)~0.72s0.72sp=1.000 n=6
Check Time9.47s (± 0.68%)9.46s (± 0.34%)~9.41s9.50sp=0.935 n=6
Emit Time2.62s (± 0.51%)2.62s (± 0.68%)~2.59s2.64sp=0.743 n=6
Total Time14.15s (± 0.62%)14.15s (± 0.23%)~14.10s14.19sp=1.000 n=6
Monaco - node (v18.15.0, x64)
Memory used347,377k (± 0.01%)347,380k (± 0.01%)~347,359k347,417kp=0.810 n=6
Parse Time2.48s (± 0.34%)2.48s (± 0.59%)~2.46s2.50sp=0.867 n=6
Bind Time0.92s (± 0.56%)0.92s (± 0.59%)~0.92s0.93sp=0.640 n=6
Check Time7.01s (± 0.42%)7.00s (± 0.28%)~6.98s7.03sp=0.324 n=6
Emit Time4.06s (± 0.43%)4.06s (± 0.34%)~4.04s4.08sp=0.871 n=6
Total Time14.49s (± 0.18%)14.47s (± 0.19%)~14.42s14.49sp=0.681 n=6
TFS - node (v18.15.0, x64)
Memory used302,689k (± 0.01%)302,713k (± 0.01%)~302,681k302,754kp=0.093 n=6
Parse Time2.44s (± 0.48%)2.42s (± 0.89%)-0.03s (- 1.02%)2.39s2.44sp=0.034 n=6
Bind Time1.20s (± 0.46%)1.20s (± 1.47%)~1.18s1.23sp=0.322 n=6
Check Time7.46s (± 0.30%)7.45s (± 0.37%)~7.42s7.50sp=0.742 n=6
Emit Time4.28s (± 0.58%)4.29s (± 0.82%)~4.24s4.33sp=0.872 n=6
Total Time15.37s (± 0.25%)15.35s (± 0.37%)~15.26s15.43sp=0.627 n=6
material-ui - node (v18.15.0, x64)
Memory used509,899k (± 0.00%)509,899k (± 0.00%)~509,885k509,920kp=1.000 n=6
Parse Time2.64s (± 0.56%)2.65s (± 0.50%)~2.63s2.66sp=0.394 n=6
Bind Time0.99s (± 0.76%)0.98s (± 1.19%)~0.96s0.99sp=0.383 n=6
Check Time17.22s (± 0.45%)17.27s (± 0.71%)~17.18s17.50sp=0.520 n=6
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)~0.00s0.00sp=1.000 n=6
Total Time20.85s (± 0.32%)20.90s (± 0.65%)~20.78s21.15sp=0.747 n=6
mui-docs - node (v18.15.0, x64)
Memory used1,737,546k (± 0.00%)1,737,562k (± 0.00%)~1,737,506k1,737,594kp=0.378 n=6
Parse Time7.76s (± 0.29%)7.80s (± 0.59%)~7.76s7.88sp=0.122 n=6
Bind Time2.79s (± 0.67%)2.81s (± 1.18%)~2.76s2.86sp=0.373 n=6
Check Time66.65s (± 0.38%)66.61s (± 0.49%)~66.14s66.99sp=0.748 n=6
Emit Time0.15s (± 3.53%)0.15s (± 2.69%)~0.15s0.16sp=0.282 n=6
Total Time77.36s (± 0.34%)77.37s (± 0.39%)~76.87s77.72sp=1.000 n=6
self-build-src - node (v18.15.0, x64)
Memory used2,394,576k (± 0.03%)2,394,386k (± 0.02%)~2,393,918k2,394,850kp=0.378 n=6
Parse Time6.05s (± 1.49%)6.05s (± 0.44%)~6.02s6.08sp=0.575 n=6
Bind Time2.26s (± 0.97%)2.25s (± 0.96%)~2.24s2.29sp=0.931 n=6
Check Time39.43s (± 0.22%)39.48s (± 0.39%)~39.29s39.72sp=0.689 n=6
Emit Time3.14s (± 1.17%)3.13s (± 1.28%)~3.09s3.19sp=0.873 n=6
Total Time50.89s (± 0.20%)50.92s (± 0.29%)~50.70s51.13sp=0.630 n=6
self-compiler - node (v18.15.0, x64)
Memory used415,193k (± 0.00%)415,235k (± 0.01%)+42k (+ 0.01%)415,187k415,270kp=0.031 n=6
Parse Time3.41s (± 1.15%)3.40s (± 1.31%)~3.34s3.46sp=0.515 n=6
Bind Time1.29s (± 0.94%)1.28s (± 0.77%)~1.27s1.29sp=0.507 n=6
Check Time18.07s (± 0.36%)18.07s (± 0.34%)~17.99s18.16sp=0.936 n=6
Emit Time1.34s (± 1.19%)1.31s (± 1.04%)-0.03s (- 2.11%)1.29s1.33sp=0.015 n=6
Total Time24.11s (± 0.35%)24.07s (± 0.42%)~23.97s24.23sp=0.572 n=6
vscode - node (v18.15.0, x64)
Memory used2,890,201k (± 0.00%)2,890,195k (± 0.00%)~2,890,082k2,890,313kp=0.873 n=6
Parse Time12.93s (± 0.52%)12.93s (± 0.27%)~12.88s12.98sp=0.810 n=6
Bind Time4.12s (± 0.42%)4.12s (± 0.36%)~4.11s4.14sp=1.000 n=6
Check Time71.71s (± 0.55%)71.52s (± 0.37%)~71.21s71.86sp=0.378 n=6
Emit Time19.44s (± 0.36%)19.45s (± 0.52%)~19.33s19.62sp=1.000 n=6
Total Time108.20s (± 0.44%)108.03s (± 0.30%)~107.72s108.59sp=0.689 n=6
webpack - node (v18.15.0, x64)
Memory used408,148k (± 0.01%)408,114k (± 0.01%)~408,077k408,140kp=0.092 n=6
Parse Time3.91s (± 0.53%)3.90s (± 0.53%)~3.87s3.93sp=0.223 n=6
Bind Time1.69s (± 0.61%)1.67s (± 1.05%)~1.66s1.70sp=0.249 n=6
Check Time16.73s (± 0.43%)16.75s (± 0.41%)~16.67s16.86sp=0.748 n=6
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)~0.00s0.00sp=1.000 n=6
Total Time22.34s (± 0.35%)22.33s (± 0.31%)~22.25s22.43sp=0.936 n=6
xstate - node (v18.15.0, x64)
Memory used513,082k (± 0.02%)512,993k (± 0.02%)~512,925k513,136kp=0.066 n=6
Parse Time3.95s (± 0.41%)4.01s (± 4.24%)~3.92s4.35sp=0.746 n=6
Bind Time1.86s (± 0.88%)1.84s (± 0.74%)~1.82s1.86sp=0.085 n=6
Check Time3.39s (± 0.86%)3.36s (± 0.15%)~3.36s3.37sp=0.100 n=6
Emit Time0.09s (± 4.62%)0.09s (± 6.44%)~0.08s0.09sp=0.282 n=6
Total Time9.27s (± 0.38%)9.30s (± 1.74%)~9.20s9.62sp=0.336 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Angular - node (v18.15.0, x64)
  • Compiler-Unions - node (v18.15.0, x64)
  • Monaco - node (v18.15.0, x64)
  • TFS - node (v18.15.0, x64)
  • material-ui - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

Developer Information:

Download Benchmarks

@RyanCavanaugh

Copy link
Copy Markdown
Member

I think there's a possible parsing ambiguity in the referenced comment

Note that this does not apply to functions with union return types that include undefined

Foo | (() => undefined) vs () => (Foo | undefined)

@typescript-bot

Copy link
Copy Markdown
Contributor

Jake Bailey (@jakebailey) Here are the results of running the top 400 repos comparing main and refs/pull/57912/merge:

Everything looks good!

@Andarist

Copy link
Copy Markdown
ContributorAuthor

The single reported failure here comes from those lines here. We can quickly verify on this TS playground that the contextual type of this function is (name: string) => string | undefined. So it makes sense that the error went away with this PR.

…turn-contextual-union
# Conflicts:
#	tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.types
#	tests/baselines/reference/inferenceDoesNotAddUndefinedOrNull.types
Comment on lines 32 to 34
const f21: () => undefined | number = () => {
~~~
!!! error TS2322: Type '() => void' is not assignable to type '() => number | undefined'.
!!! error TS2322: Type 'void' is not assignable to type 'number | undefined'.
// Error, regular void function because contextual type for implicit return isn't just undefined
// Ok, contextual type for implicit return contains undefined
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not the right person to review this, because I personally lean strongly toward the belief that distinctions between return, return undefined, and no return belong in a linter and not in TS, which I think is not the consensus view on the team. I can’t tell whether the design meeting notes on this were meant to be descriptive or prescriptive:

But no implicit returns when you have 4 | undefined

If it was intended to be prescriptive, this baseline change violates the intention that was captured in the notes. However, moving in this direction is my preference, so I’m going to approve in hopes that it moves the review along 🤷‍♂️

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that was descriptive, stating what the current behavior is and that it's inconsistent.

@jakebailey
Jake Bailey (jakebailey) merged commit f6f4eab into microsoft:mainOct 30, 2025
31 checks passed
@github-project-automationgithub-project-automationBot moved this from Needs merge to Done in PR BacklogOct 30, 2025
@microsoftMicrosoft (microsoft) locked as resolved and limited conversation to collaborators Apr 28, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

For Backlog BugPRs that fix a backlog bug

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Return type incorrectly inferred as void

7 participants

@Andarist@jakebailey@typescript-bot@RyanCavanaugh@andrewbranch@sandersn@ahejlsberg