Skip to content

Narrow String#toLowerCase/toUpperCase return types via Lowercase/Uppercase - #63460

Open
ljharb wants to merge 1 commit into
microsoft:mainfrom
ljharb:lib-string-tocase-literal-types
Open

Narrow String#toLowerCase/toUpperCase return types via Lowercase/Uppercase#63460
ljharb wants to merge 1 commit into
microsoft:mainfrom
ljharb:lib-string-tocase-literal-types

Conversation

@ljharb

Copy link
Copy Markdown
Contributor

Make String.prototype.toLowerCase and toUpperCase preserve string-literal types in their return type, by typing them as
<T extends string>(this: T): Lowercase<T> and Uppercase<T> respectively.

For non-literal string receivers, Lowercase<string> resolves to string, preserving existing behavior. For literal receivers (e.g. "FOO".toLowerCase()), the result narrows to the corresponding literal ("foo").

Also filed as microsoft/typescript-go#3711

CopilotAI review requested due to automatic review settings May 5, 2026 16:51
@typescript-bottypescript-bot added For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels May 5, 2026
@github-project-automationgithub-project-automationBot moved this to Not started in PR BacklogMay 5, 2026
@typescript-bot

Copy link
Copy Markdown
Contributor

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

1 similar comment
@typescript-bot

Copy link
Copy Markdown
Contributor

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

CopilotAI reviewed May 5, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@RyanCavanaugh

Copy link
Copy Markdown
Member

#44268 is not approved

@Renegade334

Copy link
Copy Markdown
Contributor

For non-literal string receivers, Lowercase<string> resolves to string, preserving existing behavior. For literal receivers (e.g. "FOO".toLowerCase()), the result narrows to the corresponding literal ("foo").

That's not the case, Lowercase<string> isn't flattened to string.

interfaceString{foo<Textendsstring>(this: T): Lowercase<T>;}functionreturnFoo(s: string){returns.foo();}letx=returnFoo("bar");// ^ Lowercase<string>x=escape(x);// TS2322: Type 'string' is not assignable to type 'Lowercase<string>'.

@ljharb

Copy link
Copy Markdown
ContributorAuthor

whoops. i'll try to fix that.

…rcase
Make String.prototype.toLowerCase and toUpperCase preserve string-literal
types in their return type, by typing them as
`<T extends string>(this: T): Lowercase<T>` and `Uppercase<T>` respectively.
For non-literal `string` receivers, `Lowercase<string>` resolves to `string`,
preserving existing behavior. For literal receivers (e.g. `"FOO".toLowerCase()`),
the result narrows to the corresponding literal (`"foo"`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ljharb
ljharbforce-pushed the lib-string-tocase-literal-types branch from c10ff7d to 7d2272dCompareMay 5, 2026 21:47
@ljharb

Copy link
Copy Markdown
ContributorAuthor

@RyanCavanaugh sorry, i didn't realize there was an issue already. is there any reason it can't be approved now?

@RyanCavanaugh

Copy link
Copy Markdown
Member

Is there any reason it can't be approved now?

See discussion in the "Read More" valley starting at #44268 (comment)

@ljharb

Copy link
Copy Markdown
ContributorAuthor

Thanks, and fair on the "default -100" - but i don't think it should matter if something breaks someone modifying globals or global types; that's the risk they're taking. i'm pretty sure it wouldn't break anyone who was already "polyfilling" this change (as i'm doing). As far as introducing a new type error, if they're using a literal type already, presumably they want it to stay as such, otherwise it'd already be typed as string, no?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Uncommitted BugPR for untriaged, rejected, closed or missing bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

5 participants

@ljharb@typescript-bot@RyanCavanaugh@Renegade334