From e9dc14c62341d68daf8ae00174fb0bf7e2710885 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 14 Oct 2025 02:49:03 +0100 Subject: [PATCH] fix types --- packages/emitter/src/emitter.ts | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/emitter/src/emitter.ts b/packages/emitter/src/emitter.ts index ff7e241..73f27a0 100644 --- a/packages/emitter/src/emitter.ts +++ b/packages/emitter/src/emitter.ts @@ -48,6 +48,9 @@ import type { LexCidLink, LexRefVariant, LexToken, + LexBoolean, + LexInteger, + LexString, } from "./types.js"; import { @@ -415,7 +418,7 @@ export class TypelexEmitter { // Apply @default decorator if present const rawDefault = getDefault(this.program, scalar); const defaultValue = this.processDefaultValue(rawDefault); - let defWithDefault: any = { ...scalarDef }; + let defWithDefault: LexObjectProperty = { ...scalarDef }; if (defaultValue !== undefined) { // Check if it's a Type (model reference for tokens) @@ -431,7 +434,14 @@ export class TypelexEmitter { } else { // Validate that the default value matches the type this.assertValidValueForType(scalarDef.type, defaultValue, scalar); - defWithDefault = { ...defWithDefault, default: defaultValue }; + // Type-safe narrowing based on both the type discriminator and value type + if (scalarDef.type === "boolean" && typeof defaultValue === "boolean") { + (defWithDefault as LexBoolean).default = defaultValue; + } else if (scalarDef.type === "integer" && typeof defaultValue === "number") { + (defWithDefault as LexInteger).default = defaultValue; + } else if (scalarDef.type === "string" && typeof defaultValue === "string") { + (defWithDefault as LexString).default = defaultValue; + } } } @@ -439,11 +449,11 @@ export class TypelexEmitter { if (scalarDef.type === "integer") { const minValue = getMinValue(this.program, scalar); if (minValue !== undefined) { - (defWithDefault as any).minimum = minValue; + (defWithDefault as LexInteger).minimum = minValue; } const maxValue = getMaxValue(this.program, scalar); if (maxValue !== undefined) { - (defWithDefault as any).maximum = maxValue; + (defWithDefault as LexInteger).maximum = maxValue; } } @@ -474,7 +484,7 @@ export class TypelexEmitter { // Apply @default decorator if present const rawDefault = getDefault(this.program, union); const defaultValue = this.processDefaultValue(rawDefault); - let defWithDefault: any = { ...unionDef }; + let defWithDefault: LexString = { ...unionDef as LexString }; if (defaultValue !== undefined) { // Check if it's a Type (model reference for tokens) @@ -517,7 +527,7 @@ export class TypelexEmitter { `Use @inline to inline them at usage sites, use @token models for known values, or use string literals.`, target: union, }); - } else if (unionDef.type === "integer" && (unionDef as any).enum) { + } else if (unionDef.type === "integer" && (unionDef as LexInteger).enum) { // Integer enums can also be defs const defName = name.charAt(0).toLowerCase() + name.slice(1); const description = getDoc(this.program, union); @@ -525,7 +535,7 @@ export class TypelexEmitter { // Apply @default decorator if present const rawDefault = getDefault(this.program, union); const defaultValue = this.processDefaultValue(rawDefault); - let defWithDefault = { ...unionDef }; + let defWithDefault: LexInteger = { ...unionDef as LexInteger }; if (defaultValue !== undefined) { if (typeof defaultValue === "number") { @@ -645,7 +655,7 @@ export class TypelexEmitter { // Check for default value: property default takes precedence, then union's @default let defaultValue: string | number | boolean | undefined; if (prop?.defaultValue !== undefined) { - defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as any; + defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as string | number | boolean; } else { // If no property default, check union's @default decorator const rawUnionDefault = getDefault(this.program, unionType); @@ -681,7 +691,7 @@ export class TypelexEmitter { // Check for default value: property default takes precedence, then union's @default let defaultValue: string | number | boolean | undefined; if (prop?.defaultValue !== undefined) { - defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as any; + defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as string | number | boolean; } else { // If no property default, check union's @default decorator const rawUnionDefault = getDefault(this.program, unionType); @@ -1452,10 +1462,12 @@ export class TypelexEmitter { const propDefault = serializeValueAsJson(this.program, prop.defaultValue, prop); // For union defaults that are model references, we need to resolve them for comparison - let resolvedUnionDefault: string | number | boolean | undefined = unionDefault as any; + let resolvedUnionDefault: string | number | boolean | undefined; if (unionDefault && typeof unionDefault === 'object' && 'kind' in unionDefault && unionDefault.kind === 'Model') { const ref = this.getModelReference(unionDefault as Model, true); resolvedUnionDefault = ref || undefined; + } else { + resolvedUnionDefault = unionDefault as string | number | boolean; } // If the union has a different default, or if the property has a default but the union doesn't, error -- 2.51.2