Skip to content

Commit

Permalink
feat: fix types inference for object groups
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Oct 31, 2024
1 parent 85f0793 commit da520a9
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 13 deletions.
26 changes: 13 additions & 13 deletions src/schema/object/group_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ObjectGroup } from './group.js'
import { CamelCase } from '../camelcase_types.js'
import { GroupConditional } from './conditional.js'
import { OTYPE, COTYPE, ITYPE } from '../../symbols.js'
import type { FieldContext, SchemaTypes } from '../../types.js'
import type { FieldContext, SchemaTypes, UndefinedOptional } from '../../types.js'

/**
* Create an object group. Groups are used to conditionally merge properties
Expand All @@ -32,15 +32,15 @@ group.if = function groupIf<Properties extends Record<string, SchemaTypes>>(
) {
return new GroupConditional<
Properties,
{
UndefinedOptional<{
[K in keyof Properties]: Properties[K][typeof ITYPE]
},
{
}>,
UndefinedOptional<{
[K in keyof Properties]: Properties[K][typeof OTYPE]
},
{
}>,
UndefinedOptional<{
[K in keyof Properties as CamelCase<K & string>]: Properties[K][typeof COTYPE]
}
}>
>(conditon, properties)
}

Expand All @@ -52,14 +52,14 @@ group.else = function groupElse<Properties extends Record<string, SchemaTypes>>(
) {
return new GroupConditional<
Properties,
{
UndefinedOptional<{
[K in keyof Properties]: Properties[K][typeof ITYPE]
},
{
}>,
UndefinedOptional<{
[K in keyof Properties]: Properties[K][typeof OTYPE]
},
{
}>,
UndefinedOptional<{
[K in keyof Properties as CamelCase<K & string>]: Properties[K][typeof COTYPE]
}
}>
>(() => true, properties)
}
55 changes: 55 additions & 0 deletions tests/types/types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,61 @@ test.group('Types | Object groups', () => {
>()
})

test('infer types with optional children', ({ expectTypeOf }) => {
const guideSchema = vine.group([
vine.group.if((data) => vine.helpers.isTrue(data.hiring_guide), {
hiring_guide: vine.literal(true),
guide_name: vine.string(),
fees: vine.string().optional(),
}),
vine.group.if(() => true, {
hiring_guide: vine.literal(false),
}),
])

const schema = vine
.object({
visitor_name: vine.string().optional(),
})
.merge(guideSchema)
.optional()

type InputsSchema = InferInput<typeof schema>
expectTypeOf<InputsSchema>().toEqualTypeOf<
| ({
visitor_name?: string | undefined | null
} & (
| {
hiring_guide: true
guide_name: string
fees?: string | undefined | null
}
| {
hiring_guide: false
}
))
| null
| undefined
>()

type Schema = Infer<typeof schema>
expectTypeOf<Schema>().toEqualTypeOf<
| ({
visitor_name?: string | undefined
} & (
| {
hiring_guide: true
guide_name: string
fees?: string | undefined
}
| {
hiring_guide: false
}
))
| undefined
>()
})

test('infer types with multiple groups', ({ expectTypeOf }) => {
const guideSchema = vine.group([
vine.group.if((data) => vine.helpers.isTrue(data.hiring_guide), {
Expand Down

0 comments on commit da520a9

Please sign in to comment.