Convert string | URL unions to strings through the URL's href

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Malte Ubl
2026-10-19 17:31:37 -07:00
co-authored by Claude Opus 5.5
parent b8dd7d2182
commit 4993060d16
3 changed files with 33 additions and 3 deletions
@@ -270,8 +270,8 @@ function refuse(lowerer: Lowerer, node: ts.Node, info: ClassInfo, what: string):
}
/** ToString(ToPrimitive(value, hint)) of a union whose arms are program
* class instances and primitives (`Box | undefined`): each arm converts as
* it would alone. Null for other unions. */
* class instances, URLs and primitives (`Box | undefined`, `string | URL`):
* each arm converts as it would alone. Null for other unions. */
export function classUnionToString(
lowerer: Lowerer,
value: IrExpr,
@@ -281,9 +281,11 @@ export function classUnionToString(
if (value.type.kind !== "union") return null;
const unionId = value.type.unionId;
const arms = lowerer.unions.get(unionId)?.arms;
if (!arms || !arms.some((arm) => arm.kind === "object")) return null;
if (!arms || !arms.some((arm) => arm.kind === "object" || arm.kind === "url")) return null;
const convertible = (arm: IrType): boolean => {
if (PRIMITIVE_KINDS.has(arm.kind)) return true;
// A URL arm converts through its href, like String(url).
if (arm.kind === "url") return true;
if (arm.kind !== "object") return false;
const info = lowerer.classes.get(arm.className);
return info !== undefined && plainProgramClass(info);
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6250-string-of-string-or-url.ts"
],
"diags": []
}
@@ -0,0 +1,22 @@
// String(), template literals and concatenation over a `string | URL`
// union: the string arm passes through and the URL arm converts through its
// href, exactly as each would alone (an origin URL keeps its trailing
// slash, the origin string does not).
function key(origin: string | URL): string {
return String(origin);
}
function label(origin: string | URL | undefined): string {
return `[${origin}]`;
}
const url = new URL("http://127.0.0.1:8080");
console.log(key("http://127.0.0.1:8080"));
console.log(key(url));
console.log(key(new URL("https://example.com/a/b?x=1#h")));
console.log(label(url), label("plain"), label(undefined));
const both: (string | URL)[] = ["a", url];
console.log(both.map((o) => "" + o).join(" "));
const map = new Map<string, number>();
map.set(key(url.origin), 1);
console.log(map.get(String(url.origin)), map.get(String(url)));