mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Memoize an empty literal's type separately as a union arm
The type mapper maps the type inferred from an empty object literal to the empty record as an arm of an unreduced union and to a checked-dynamic value elsewhere, but both answers shared one memo entry. Once the type had been mapped on its own, a union such as `typeof empty | DataView` reused the dynamic answer for its arm and refused (SC2009). The memo key now includes whether the mapping is for such an arm.
This commit is contained in:
@@ -1655,7 +1655,10 @@ export function mapType(type: ts.Type, ctx: TypeMapperCtx): IrType | null {
|
||||
const topLevel = mapTypeDepth === 0;
|
||||
const typeId = (type as { id?: number }).id;
|
||||
const memoizable = typeId !== undefined && (ctx.canMemoizeType?.() ?? true);
|
||||
const memoKey = memoizable ? `${0}:${typeId}` : null;
|
||||
// An empty literal's type maps to the empty record as an unreduced union's
|
||||
// arm (emptyLiteralArm) and to the checked-dynamic value elsewhere: the two
|
||||
// answers keep separate memo entries.
|
||||
const memoKey = memoizable ? `${ctx.emptyLiteralArm ? 1 : 0}:${typeId}` : null;
|
||||
if (memoKey !== null) {
|
||||
const memo = ctx.typeMemo?.get(memoKey);
|
||||
if (memo !== undefined) return memo;
|
||||
|
||||
@@ -30,3 +30,11 @@ console.log(typeof choose(1), typeof choose(-1));
|
||||
|
||||
const empty = {};
|
||||
console.log(JSON.stringify(empty), Object.keys(empty).length, empty === empty, String(empty));
|
||||
|
||||
// An empty literal's type beside a typed arm of an unreduced union, after
|
||||
// the type was already used on its own.
|
||||
const viewed = {};
|
||||
console.log(JSON.stringify(viewed));
|
||||
const views: (typeof viewed | DataView)[] = [viewed, new DataView(new ArrayBuffer(2))];
|
||||
for (const view of views)
|
||||
console.log(view instanceof DataView ? `view ${view.byteLength}` : JSON.stringify(view));
|
||||
|
||||
Reference in New Issue
Block a user