mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
Spreading a falsy primitive copies nothing, so `...(cond && { k: v })` is
the optional-field idiom `...(cond ? { k: v } : {})`. The `&&` spelling
(the @edge-runtime/cookies parseSetCookie shape) was refused with a record
shape mismatch (SC2002).
When the spread's type mixes the record with primitive arms, the literal
lowering now uses the existing conditional-spread desugar: cond evaluates
once, v only when taken, and the absent arm leaves the optional field
undefined. Record and record-or-unit spreads keep the source-copy path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38 lines
1.5 KiB
TypeScript
38 lines
1.5 KiB
TypeScript
// `...(cond && { k: v })` spreads nothing when cond is a falsy primitive
|
|
// (false, 0, ""), so it is the optional-field idiom `...(cond ? { k: v } : {})`:
|
|
// cond evaluates once, v only when taken. (Fields print one by one: the
|
|
// declared-shape property order of spread-built records is a documented
|
|
// limitation.)
|
|
type C = { name: string; name2: string; httpOnly?: boolean; maxAge?: number; path?: string; sameSite?: string };
|
|
function parse(attrs: Record<string, string | undefined>, flag: boolean): C {
|
|
const httponly = attrs.httponly;
|
|
const maxage = attrs["max-age"];
|
|
const samesite = attrs.samesite;
|
|
let calls = 0;
|
|
const lower = (s: string): string => {
|
|
calls++;
|
|
return s.toLowerCase();
|
|
};
|
|
const c: C = {
|
|
name: "a",
|
|
...(flag && { httpOnly: true }),
|
|
...(httponly && { path: httponly }),
|
|
...(typeof maxage === "string" && { maxAge: Number(maxage) }),
|
|
name2: "/",
|
|
...(samesite && { sameSite: lower(samesite) }),
|
|
};
|
|
console.log("calls", calls);
|
|
return c;
|
|
}
|
|
for (const [attrs, flag] of [
|
|
[{}, false],
|
|
[{ httponly: "yes", "max-age": "10", samesite: "Lax" }, true],
|
|
[{ httponly: "", "max-age": "", samesite: "" }, true],
|
|
] as [Record<string, string | undefined>, boolean][]) {
|
|
const c = parse(attrs, flag);
|
|
console.log(c.name, c.name2, c.httpOnly, c.path, c.maxAge, c.sameSite, "httpOnly" in c, "path" in c);
|
|
}
|
|
const n: number = Number(process.argv.length > 99 ? "1" : "0");
|
|
const d: { v?: number; name: string } = { name: "n", ...(n && { v: n }) };
|
|
console.log(d.name, d.v, "v" in d);
|