Skip to content

Commit c489464

Browse files
authored
Revision 0.33.2 (#947)
* Retain Interior Properties on Pick, Omit and Mapped Types * Version
1 parent b00293e commit c489464

File tree

7 files changed

+81
-21
lines changed

7 files changed

+81
-21
lines changed

Diff for: package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sinclair/typebox",
3-
"version": "0.33.1",
3+
"version": "0.33.2",
44
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
55
"keywords": [
66
"typescript",

Diff for: src/type/mapped/mapped.ts

+12-10
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ type FromSchemaType<K extends PropertyKey, T extends TSchema> = (
205205
)
206206
// prettier-ignore
207207
function FromSchemaType<K extends PropertyKey, T extends TSchema>(K: K, T: T): FromSchemaType<K, T> {
208+
// required to retain user defined options for mapped type
209+
const options = { ...T }
208210
return (
209211
// unevaluated modifier types
210212
IsOptional(T) ? Optional(FromSchemaType(K, Discard(T, [OptionalKind]) as TSchema)) :
@@ -213,16 +215,16 @@ function FromSchemaType<K extends PropertyKey, T extends TSchema>(K: K, T: T): F
213215
IsMappedResult(T) ? FromMappedResult(K, T.properties) :
214216
IsMappedKey(T) ? FromMappedKey(K, T.keys) :
215217
// unevaluated types
216-
IsConstructor(T) ? Constructor(FromRest(K, T.parameters), FromSchemaType(K, T.returns)) :
217-
IsFunction(T) ? FunctionType(FromRest(K, T.parameters), FromSchemaType(K, T.returns)) :
218-
IsAsyncIterator(T) ? AsyncIterator(FromSchemaType(K, T.items)) :
219-
IsIterator(T) ? Iterator(FromSchemaType(K, T.items)) :
220-
IsIntersect(T) ? Intersect(FromRest(K, T.allOf)) :
221-
IsUnion(T) ? Union(FromRest(K, T.anyOf)) :
222-
IsTuple(T) ? Tuple(FromRest(K, T.items ?? [])) :
223-
IsObject(T) ? Object(FromProperties(K, T.properties)) :
224-
IsArray(T) ? Array(FromSchemaType(K, T.items)) :
225-
IsPromise(T) ? Promise(FromSchemaType(K, T.item)) :
218+
IsConstructor(T) ? Constructor(FromRest(K, T.parameters), FromSchemaType(K, T.returns), options) :
219+
IsFunction(T) ? FunctionType(FromRest(K, T.parameters), FromSchemaType(K, T.returns), options) :
220+
IsAsyncIterator(T) ? AsyncIterator(FromSchemaType(K, T.items), options) :
221+
IsIterator(T) ? Iterator(FromSchemaType(K, T.items), options) :
222+
IsIntersect(T) ? Intersect(FromRest(K, T.allOf), options) :
223+
IsUnion(T) ? Union(FromRest(K, T.anyOf), options) :
224+
IsTuple(T) ? Tuple(FromRest(K, T.items ?? []), options) :
225+
IsObject(T) ? Object(FromProperties(K, T.properties), options) :
226+
IsArray(T) ? Array(FromSchemaType(K, T.items), options) :
227+
IsPromise(T) ? Promise(FromSchemaType(K, T.item), options) :
226228
T
227229
) as never
228230
}

Diff for: src/type/omit/omit.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function OmitResolve<T extends TSchema, K extends PropertyKey[]>(T: T, K: [...K]
9393
return (
9494
IsIntersect(T) ? Intersect(FromIntersect(T.allOf, K)) :
9595
IsUnion(T) ? Union(FromUnion(T.anyOf, K)) :
96-
IsObject(T) ? Object(FromProperties(T.properties, K)) :
96+
IsObject(T) ? Object(FromProperties(T.properties, K), Discard(T, [TransformKind, '$id', 'required'])) :
9797
Object({})
9898
) as never
9999
}
@@ -121,7 +121,5 @@ export function Omit(T: TSchema, K: any, options?: SchemaOptions): any {
121121
if (IsMappedResult(T)) return OmitFromMappedResult(T, K, options)
122122
// non-mapped
123123
const I = IsSchema(K) ? IndexPropertyKeys(K) : (K as string[])
124-
const D = Discard(T, [TransformKind, '$id', 'required']) as TSchema
125-
const R = OmitResolve(T, I)
126-
return CreateType({ ...D, ...R }, options)
124+
return CreateType(OmitResolve(T, I), options)
127125
}

Diff for: src/type/pick/pick.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function PickResolve<T extends TSchema, K extends PropertyKey[]>(T: T, K: [...K]
8686
return (
8787
IsIntersect(T) ? Intersect(FromIntersect(T.allOf, K)) :
8888
IsUnion(T) ? Union(FromUnion(T.anyOf, K)) :
89-
IsObject(T) ? Object(FromProperties(T.properties, K)) :
89+
IsObject(T) ? Object(FromProperties(T.properties, K), Discard(T, [TransformKind, '$id', 'required'])) :
9090
Object({})
9191
) as never
9292
}
@@ -112,7 +112,5 @@ export function Pick(T: TSchema, K: any, options?: SchemaOptions): any {
112112
if (IsMappedResult(T)) return PickFromMappedResult(T, K, options)
113113
// non-mapped
114114
const I = IsSchema(K) ? IndexPropertyKeys(K) : (K as string[])
115-
const D = Discard(T, [TransformKind, '$id', 'required']) as TSchema
116-
const R = PickResolve(T, I)
117-
return CreateType({ ...D, ...R }, options)
115+
return CreateType(PickResolve(T, I), options)
118116
}

Diff for: test/runtime/type/guard/type/omit.ts

+31
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,35 @@ describe('guard/type/TOmit', () => {
126126
const R = Type.Omit(S, ['x'])
127127
Assert.IsFalse(TransformKind in R)
128128
})
129+
// ----------------------------------------------------------------
130+
// https://github.com/sinclairzx81/typebox/issues/944
131+
// ----------------------------------------------------------------
132+
it('Should retain interior properties 1', () => {
133+
const A = Type.Object({ x: Type.Number() }, { additionalProperties: false })
134+
const T = Type.Omit(A, ['x'])
135+
Assert.IsFalse(T.additionalProperties as boolean)
136+
})
137+
it('Should retain interior properties 2', () => {
138+
const A = Type.Object({ x: Type.Number() }, { additionalProperties: false })
139+
const B = Type.Object({ y: Type.Number() }, { additionalProperties: false })
140+
const U = Type.Union([A, B])
141+
const T = Type.Omit(U, ['x'])
142+
Assert.IsFalse(T.anyOf[0].additionalProperties as boolean)
143+
Assert.IsFalse(T.anyOf[1].additionalProperties as boolean)
144+
})
145+
it('Should retain interior properties 3', () => {
146+
const A = Type.Object({ x: Type.Number() }, { additionalProperties: false })
147+
const B = Type.Object({ y: Type.Number() }, { additionalProperties: false })
148+
const U = Type.Intersect([A, B])
149+
const T = Type.Omit(U, ['x'])
150+
Assert.IsFalse(T.allOf[0].additionalProperties as boolean)
151+
Assert.IsFalse(T.allOf[1].additionalProperties as boolean)
152+
})
153+
it('Should retain interior properties 4', () => {
154+
const A = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false })
155+
const T = Type.Mapped(Type.TemplateLiteral('${x|y|z}'), (_) => Type.Omit(A, ['x']))
156+
Assert.IsFalse(T.properties.x.additionalProperties as boolean)
157+
Assert.IsFalse(T.properties.y.additionalProperties as boolean)
158+
Assert.IsFalse(T.properties.z.additionalProperties as boolean)
159+
})
129160
})

Diff for: test/runtime/type/guard/type/pick.ts

+31
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,35 @@ describe('guard/type/TPick', () => {
128128
const R = Type.Pick(S, ['x'])
129129
Assert.IsFalse(TransformKind in R)
130130
})
131+
// ----------------------------------------------------------------
132+
// https://github.com/sinclairzx81/typebox/issues/944
133+
// ----------------------------------------------------------------
134+
it('Should retain interior properties 1', () => {
135+
const A = Type.Object({ x: Type.Number() }, { additionalProperties: false })
136+
const T = Type.Pick(A, ['x'])
137+
Assert.IsFalse(T.additionalProperties as boolean)
138+
})
139+
it('Should retain interior properties 2', () => {
140+
const A = Type.Object({ x: Type.Number() }, { additionalProperties: false })
141+
const B = Type.Object({ y: Type.Number() }, { additionalProperties: false })
142+
const U = Type.Union([A, B])
143+
const T = Type.Pick(U, ['x'])
144+
Assert.IsFalse(T.anyOf[0].additionalProperties as boolean)
145+
Assert.IsFalse(T.anyOf[1].additionalProperties as boolean)
146+
})
147+
it('Should retain interior properties 3', () => {
148+
const A = Type.Object({ x: Type.Number() }, { additionalProperties: false })
149+
const B = Type.Object({ y: Type.Number() }, { additionalProperties: false })
150+
const U = Type.Intersect([A, B])
151+
const T = Type.Pick(U, ['x'])
152+
Assert.IsFalse(T.allOf[0].additionalProperties as boolean)
153+
Assert.IsFalse(T.allOf[1].additionalProperties as boolean)
154+
})
155+
it('Should retain interior properties 4', () => {
156+
const A = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false })
157+
const T = Type.Mapped(Type.TemplateLiteral('${x|y|z}'), (_) => Type.Pick(A, ['x']))
158+
Assert.IsFalse(T.properties.x.additionalProperties as boolean)
159+
Assert.IsFalse(T.properties.y.additionalProperties as boolean)
160+
Assert.IsFalse(T.properties.z.additionalProperties as boolean)
161+
})
131162
})

0 commit comments

Comments
 (0)