Skip to content

Value.Cast with Type.Intersect produces incorrect result when partial nested objects are provided #1264

@DemonHa

Description

@DemonHa

When using Value.Cast with a schema defined using Type.Intersect, nested object properties are not correctly coerced if the input contains a partial object. The casting will use the default values even when some values are provided.

Minimal reproduction

const schema = Type.Intersect([
  Type.Object({}),
  Type.Object({
    name: Type.String(),
    age: Type.Optional(Type.Number()),
    location: Type.Object({
      lat: Type.Number(),
      long: Type.Number(),
    }),
    greeting: Type.String(),
  }),
])

const result = coerceValue(schema, { location: {}, greeting: 'Hello' })

// ❌ Actual output:
{
  greeting: '',
  location: { lat: 0, long: 0 },
  name: ''
}

// ✅ Expected output:
{
  greeting: 'Hello',
  location: { lat: 0, long: 0 },
  name: ''
}

console.log(result)

✅ Notes:

  • If the location field is removed, the result is correct:
const result2 = coerceValue(schema, { greeting: 'Hello' })
// Output: { greeting: 'Hello', location: { lat: 0, long: 0 }, name: '' }
  • Replacing Type.Intersect with Type.Composite resolves the casting issue:
const schema = Type.Composite([...])
const result = coerceValue(schema, { location: {}, greeting: 'Hello' })
// Output: { greeting: 'Hello', location: { lat: 0, long: 0 }, name: '' }

⚠️ Problem with Type.Composite:

The return type is no longer correct when using features like Type.TemplateLiteral with Type.Record. For example:

const schema = Type.Composite([
  Type.Record(Type.TemplateLiteral('x-${string}'), Type.Unknown()),
  Type.Object({
    name: Type.String(),
    ...
  })
])
type t = Static<typeof schema> // Incorrect type inference

✅ Type inference works correctly when using Type.Intersect.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions