-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Fixed an issue with mapped property symbol not displaying added | undefined when its origin symbol was optional
#59957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fixed an issue with mapped property symbol not displaying added | undefined when its origin symbol was optional
#59957
Conversation
…defined` when its origin symbol was optional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes an issue where mapped property symbols weren't displaying | undefined when their origin symbol was optional. The fix ensures that when TypeScript displays type information for mapped types, it correctly shows the union with undefined for properties that originated from optional properties.
- Refactors the
requiresAddingImplicitUndefinedfunction to improve readability and fix the logic for determining when to add implicit undefined - Adds comprehensive test coverage with 5 new fourslash tests covering various scenarios of mapped types with optional properties
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/compiler/checker.ts | Refactors the logic in requiresAddingImplicitUndefined to use early returns and adds proper type checking for declared types |
| tests/cases/fourslash/quickInfoMappedPropertyUnionUndefined1.ts | Tests mapped type behavior with exactOptionalPropertyTypes enabled |
| tests/cases/fourslash/quickInfoMappedPropertyUnionUndefined2.ts | Tests mapped type behavior in standard strict mode |
| tests/cases/fourslash/quickInfoMappedPropertyUnionUndefined3.ts | Tests nested mapped type transformations |
| tests/cases/fourslash/quickInfoMappedPropertyUnionUndefined4.ts | Tests simple mapped type with required modifier |
| tests/cases/fourslash/quickInfoMappedPropertyUnionUndefined5.ts | Tests RequiredKeys utility type scenario |
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | ||
| //// type Literal/*2*/ = { a?: string | undefined }; | ||
| //// | ||
| //// type Res1/*3*/ = Required<Intermidiate>; | ||
| //// type Res2/*4*/ = Required<Literal>; | ||
|
|
||
| verify.quickInfoAt("1", `type Intermidiate = { |
Copilot
AI
Aug 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type name 'Intermidiate' is misspelled. It should be 'Intermediate'.
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermidiate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermidiate = { | |
| //// type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermediate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermediate = { |
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | ||
| //// type Literal/*2*/ = { a?: string | undefined }; | ||
| //// | ||
| //// type Res1/*3*/ = Required<Intermidiate>; | ||
| //// type Res2/*4*/ = Required<Literal>; | ||
|
|
||
| verify.quickInfoAt("1", `type Intermidiate = { |
Copilot
AI
Aug 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type name 'Intermidiate' is misspelled. It should be 'Intermediate'.
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermidiate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermidiate = { | |
| //// type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermediate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermediate = { |
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | ||
| //// type Literal/*2*/ = { a?: string | undefined }; | ||
| //// | ||
| //// type Res1/*3*/ = Required<Intermidiate>; | ||
| //// type Res2/*4*/ = Required<Literal>; | ||
|
|
||
| verify.quickInfoAt("1", `type Intermidiate = { |
Copilot
AI
Aug 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type name 'Intermidiate' is misspelled. It should be 'Intermediate'.
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermidiate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermidiate = { | |
| //// type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermediate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermediate = { |
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | ||
| //// type Literal/*2*/ = { a?: string | undefined }; | ||
| //// | ||
| //// type Res1/*3*/ = Required<Intermidiate>; | ||
| //// type Res2/*4*/ = Required<Literal>; | ||
|
|
||
| verify.quickInfoAt("1", `type Intermidiate = { |
Copilot
AI
Aug 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type name 'Intermidiate' is misspelled. It should be 'Intermediate'.
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermidiate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermidiate = { | |
| //// type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermediate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermediate = { |
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | ||
| //// type Literal/*2*/ = { a?: string | undefined }; | ||
| //// | ||
| //// type Res1/*3*/ = Required<Intermidiate>; | ||
| //// type Res2/*4*/ = Required<Literal>; | ||
|
|
||
| verify.quickInfoAt("1", `type Intermidiate = { |
Copilot
AI
Aug 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type name 'Intermidiate' is misspelled. It should be 'Intermediate'.
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermidiate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermidiate = { | |
| //// type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermediate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermediate = { |
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | ||
| //// type Literal/*2*/ = { a?: string | undefined }; | ||
| //// | ||
| //// type Res1/*3*/ = Required<Intermidiate>; | ||
| //// type Res2/*4*/ = Required<Literal>; | ||
|
|
||
| verify.quickInfoAt("1", `type Intermidiate = { |
Copilot
AI
Aug 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type name 'Intermidiate' is misspelled. It should be 'Intermediate'.
| //// type Intermidiate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermidiate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermidiate = { | |
| //// type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; | |
| //// type Literal/*2*/ = { a?: string | undefined }; | |
| //// | |
| //// type Res1/*3*/ = Required<Intermediate>; | |
| //// type Res2/*4*/ = Required<Literal>; | |
| verify.quickInfoAt("1", `type Intermediate = { |
fixes #59948
fixes #60411
fixes #62325