-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Value.Clone corrupts Object instance #1186
Comments
@bitofbreeze Hi,
Interesting. The minimum requirements for Clone is that the properties and symbols of an object are enumerable Try the following and let me know what it prints. const cloned = structuredClone(value.KV)
const symbols = Object.getOwnPropertySymbols(value.KV)
const keys = Object.getOwnPropertyNames(value.KV)
console.log({ cloned, symbols, keys }) If keys returns an empty array, it means the const result = Value.Parse([
// 'Clone', // omit
'Clean', // ... and keep these
'Default',
'Convert',
'Assert',
'Decode'
], schema, value.KV) Let me know what you see for the above |
@sinclairzx81 structuredClone gives The other two give Thanks for the tip about just not cloning. Also to clarify, I mean using the spread on the entire Maybe you could add this check in the Clone method: |
@bitofbreeze Hiya,
It won't be possible for TypeBox make calls to runtime specific functions (be it Node, Deno, Bun or even Browser API's) as this would couple TypeBox to that runtime. You can however override the default Clone to perform the import { Value, ParseRegistry } from '@sinclair/typebox/value'
ParseRegistry.Set('Clone', (_schema, _references, value) => {
return util.types.isProxy(value) ? value : Value.Clone(value)
})
const result = Value.Parse([
'Clone', // ... uses clone override above
'Clean',
'Default',
'Convert',
'Assert',
'Decode'
], schema, value.KV)
Indeed. The problem does stem from the way the This said, you could try ask the maintainers of the Consider the following example import { Value } from '@sinclair/typebox/value'
// virtual object
const value = new Proxy({}, {
ownKeys: () => ['x', 'y', 'z'],
get: (_, key) => {
return (
key === 'x' ? 1 :
key === 'y' ? 2 :
key === 'z' ? 3 :
undefined
)
},
// required for clone
getOwnPropertyDescriptor: () => {
return {
enumerable: true,
configurable: true
}
}
})
// enumerable test
console.log(Object.keys(value)) // ['x', 'y', 'z']
console.log(Object.getOwnPropertyNames(value)) // ['x', 'y', 'z']
console.log(Object.getOwnPropertySymbols(value)) // []
// clone test
const A = { ...value } // ok
const B = Value.Clone(value) // ok - when enumerable
const C = structuredClone(
Object.fromEntries(Object.entries(value)) // enumerable to structuredClone
)
console.log({ A, B, C })
// {
// A: { x: 1, y: 2, z: 3 },
// B: { x: 1, y: 2, z: 3 },
// C: { x: 1, y: 2, z: 3 }
// } I think I will close out this issue because there's not much TypeBox can do to Clone a non-enumerable object. If you want to implement conditional Clone via import { TSchema, StaticDecode } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
function ParseKV<Type extends TSchema, Result = StaticDecode<Type>>(type: Type, value: unknown): Result {
return Value.Parse(['Clean', 'Default', 'Convert','Assert', 'Decode'], type, value) as never
}
const result = ParseKV(Type.Unsafe<KVNamespace>(Type.Unknown()), value.KV) Happy to answer additional questions on this thread if you need, but will close this issue out for now. |
I am trying to validate a Cloudflare Worker env context, which binds a ProxyStub instance to it . I have a schema like:
and then I proceed to do the Parse steps:
which outputs:
As you can see, the cloning step seems to corrupt the value. I have tested doing a simple shallow clone in JS via the spread operator, and it preserves the binding correctly, so I am not sure what Value.Clone does that destroys it.
Simply removing the Clone step outputs the following:
which confirms the Clone step is the offender.
The text was updated successfully, but these errors were encountered: