sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
5.08k stars 161 forks source link

Module doesn't work correctly with transformation #1092

Closed sorawee closed 4 days ago

sorawee commented 4 days ago

Consider:

export function parseObject<T extends TSchema>(typ: T, obj: unknown): StaticDecode<T> {
  return Value.Decode(typ, Value.Default(typ, obj));
}

const ActualUser = Type.Transform(
  Type.Object({
    name: Type.String(),
    age: Type.Number(),
  }),
)
  .Decode((e) => ({ ...e, foobar: 42 }))
  .Encode((e) => {
    const { foobar, ...rest } = e;
    return rest;
  })

const Module = Type.Module({
  User: ActualUser,
})

const User = Module.Import('User');

console.log(parseObject(ActualUser, { name: 'abc', age: 1 })); // { name: 'abc', age: 1, foobar: 42 }
console.log(parseObject(User, { name: 'abc', age: 1 })); // { name: 'abc', age: 1 }

The transformation type works correctly when used outside of Module, but it's not run when it's imported from Module.

sinclairzx81 commented 4 days ago

@sorawee Hi,

This is currently by design (at least for now). The reason is because Modules may perform transformations to referential schematics (via Type.Ref) in cases where the type is computed (e.g Partial). Because of this, the Transform Input / Output types cannot be known interior to the Module.

You can however apply the Transform to the imported Type (as Input/Output types are known exterior to the Module)

const ActualUser = Type.Object({
  name: Type.String(),
  age: Type.Number(),
})

const Module = Type.Module({
  User: ActualUser,
})

// Apply Transform to the Import Type
const User = Type.Transform(Module.Import('User'))
.Decode((e) => ({ ...e, foobar: 42 }))
.Encode((e) => {
  const { foobar, ...rest } = e;
  return rest;
})

console.log(parseObject(ActualUser, { name: 'abc', age: 1 })); // { name: 'abc', age: 1 } 
console.log(parseObject(User, { name: 'abc', age: 1 })); // { name: 'abc', age: 1, foobar: 42 }

Will close up this issue for now as interior Module transforms are generally unsupported. I'm happy to field any additional questions you may have on this functionality on this thread.

Cheers! S