Uh oh!
There was an error while loading. Please reload this page.
Narrow String#toLowerCase/toUpperCase return types via Lowercase/Uppercase - #63460
Narrow String#toLowerCase/toUpperCase return types via Lowercase/Uppercase#63460ljharb wants to merge 1 commit into
Conversation
typescript-bot
commented
May 5, 2026
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
commented
May 5, 2026
This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise. |
RyanCavanaugh
commented
May 5, 2026
#44268 is not approved |
Renegade334
commented
May 5, 2026
That's not the case, 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
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>
c10ff7d to
7d2272dCompareljharb
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? |
RyanCavanaugh
commented
May 6, 2026
See discussion in the "Read More" valley starting at #44268 (comment) |
ljharb
commented
May 6, 2026
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 |
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>andUppercase<T>respectively.For non-literal
stringreceivers,Lowercase<string>resolves tostring, 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