Skip to content

Commit f6abdf1

Browse files
committed
🔧 fix: handle strict union check
1 parent 28bbace commit f6abdf1

File tree

5 files changed

+74
-20
lines changed

5 files changed

+74
-20
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 0.2.4 - 26 Nov 2025
2+
Improvement:
3+
- handle strict union check
4+
15
# 0.2.3 - 5 Nov 2025
26
Bug fix:
37
- [#24](https://github.com/elysiajs/exact-mirror/pull/24) bracket handling in fields

example/index.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,31 @@ import createMirror from '../src/index'
33

44
import { TypeCompiler } from '@sinclair/typebox/compiler'
55

6-
const shape = t.Object({
7-
total: t
8-
.Transform(t.Number())
9-
.Decode((x) => x)
10-
.Encode((x) => x),
11-
user: t.Object({
12-
username: t.String()
13-
}),
14-
})
6+
const SchemaA = t.Object(
7+
{ foo: t.Number() },
8+
{
9+
additionalProperties: false
10+
}
11+
)
12+
const SchemaB = t.Object(
13+
{ foo: t.Number(), baz: t.Boolean() },
14+
{
15+
additionalProperties: false
16+
}
17+
)
18+
const UnionSchema = t.Union([SchemaA, SchemaB])
19+
const OmittedUnionSchema = t.Omit(UnionSchema, ['baz'])
20+
21+
const shape = OmittedUnionSchema
1522

16-
const value = {
17-
total: 1,
18-
user: { username: 'Bob', secret: 'shhh' }
19-
} satisfies typeof shape.static
23+
const value = { baz: true, foo: 1 } satisfies typeof shape.static
2024

2125
const mirror = createMirror(shape, {
22-
TypeCompiler,
23-
sanitize: (a) => a
26+
TypeCompiler
2427
})
2528

29+
console.log(mirror.toString())
30+
2631
console.dir(mirror(value), {
2732
depth: null
2833
})

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "exact-mirror",
3-
"version": "0.2.3",
3+
"version": "0.2.4",
44
"description": "Mirror exact value to TypeBox/OpenAPI model",
55
"license": "MIT",
66
"scripts": {

src/index.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ const handleUnion = (
254254
return type
255255
}
256256

257+
// some type require cleaning before checking
258+
// e.g. object with `additionalProperties: false`
259+
let cleanThenCheck = ''
260+
257261
for (let i = 0; i < schemas.length; i++) {
258262
let type = unwrapRef(schemas[i])
259263

@@ -277,16 +281,26 @@ const handleUnion = (
277281
parentIsOptional: true
278282
}
279283
)}}\n`
284+
285+
cleanThenCheck +=
286+
(i ? '' : 'let ') +
287+
'tmp=' +
288+
mirror(type, property, {
289+
...instruction,
290+
recursion: instruction.recursion + 1,
291+
parentIsOptional: true
292+
}) +
293+
`\nif(d.unions[${ui}][${i}].Check(tmp))return tmp\n`
280294
}
281295

296+
if (cleanThenCheck) v += cleanThenCheck
297+
282298
// unknown type, return as-is (this is a default intended behavior)
283299
// because it's expected that exact-mirror input should always be a correct value
284300
// returning an incorrect value then later checked is expected
285-
v +=
286-
`return ${instruction.removeUnknownUnionType ? 'undefined' : property}` +
287-
`})()`
301+
v += `return ${instruction.removeUnknownUnionType ? 'undefined' : property}`
288302

289-
return v
303+
return v + `})()`
290304
}
291305

292306
const mirror = (

test/union.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,35 @@ describe('Union', () => {
214214
value
215215
)
216216
})
217+
218+
it('handle clean then check', () => {
219+
const SchemaA = t.Object(
220+
{ foo: t.Number() },
221+
{
222+
additionalProperties: false
223+
}
224+
)
225+
const SchemaB = t.Object(
226+
{ foo: t.Number(), baz: t.Boolean() },
227+
{
228+
additionalProperties: false
229+
}
230+
)
231+
const UnionSchema = t.Union([SchemaA, SchemaB])
232+
const OmittedUnionSchema = t.Omit(UnionSchema, ['baz'])
233+
234+
const shape = OmittedUnionSchema
235+
236+
const value = { foo: 1 } satisfies typeof shape.static
237+
238+
isEqual(
239+
shape,
240+
{
241+
// @ts-ignore
242+
baz: true,
243+
foo: 1
244+
},
245+
value
246+
)
247+
})
217248
})

0 commit comments

Comments
 (0)