Skip to content

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

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

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

Conversation

@ljharb
Copy link
Copy Markdown
Contributor

@ljharb ljharb commented May 5, 2026

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

Copilot AI review requested due to automatic review settings May 5, 2026 16:51
@typescript-bot typescript-bot added For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels May 5, 2026
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog May 5, 2026
@typescript-bot
Copy link
Copy Markdown
Collaborator

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
Collaborator

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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.

interface String {
  foo<T extends string>(this: T): Lowercase<T>;
}

function returnFoo(s: string) {
  return s.foo();
}

let x = returnFoo("bar");
//  ^ Lowercase<string>

x = escape(x);
// TS2322: Type 'string' is not assignable to type 'Lowercase<string>'.

@ljharb
Copy link
Copy Markdown
Contributor Author

ljharb commented May 5, 2026

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 ljharb force-pushed the lib-string-tocase-literal-types branch from c10ff7d to 7d2272d Compare May 5, 2026 21:47
@ljharb
Copy link
Copy Markdown
Contributor Author

ljharb commented May 5, 2026

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

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

Labels

For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

5 participants