Skip to content

Commit

Permalink
chore(lib): improve array types
Browse files Browse the repository at this point in the history
  • Loading branch information
Kosai106 committed Nov 23, 2024
1 parent 9e1ec79 commit 6bb5b77
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 25 deletions.
2 changes: 1 addition & 1 deletion packages/validathor/src/guards/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Parser } from '@/types'

export const isParser = <T>(input: unknown): input is T => {
return input !== null && typeof input === 'object' && 'parse' in input
return input !== null && typeof input === 'object' && 'parse' in input && 'name' in input
}

export const isParserRecords = <T extends Record<string, Parser<unknown>>>(
Expand Down
9 changes: 5 additions & 4 deletions packages/validathor/src/schemas/__tests__/array.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,11 @@ describe('array()', () => {
})
})

describe('[FUTURE]', () => {
it.fails('should work with mixed schemas', () => {
const schema = array<string | number>([string(), number()])

describe('[FUTURE] mixed schemas', () => {
it.fails.each([
array<string | number>([string(), number()]),
array<number | string>([number(), string()]),
])('should work with mixed schemas', (schema) => {
expect(parse(schema, ['hello', 'world', 123])).toEqual(['hello', 'world', 123])
expect(() => parse(schema, ['foo', true, 'baz'])).toThrowError(
new TypeError('Value must be at most 2 x long'),
Expand Down
52 changes: 32 additions & 20 deletions packages/validathor/src/schemas/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,40 @@ type AcceptedParserPrimitives =
| boolean
| Date
| object
| Array<AcceptedParserPrimitives>
| AcceptedParserPrimitives[]

type ParserMap = {
string: Parser<string>
number: Parser<number>
boolean: Parser<boolean>
Date: Parser<Date>
object: Parser<object>
Array: Parser<Array<AcceptedParserPrimitives>>
Array: Parser<AcceptedParserPrimitives[]>
}

type GetParser<T> = T extends keyof ParserMap ? ParserMap[T] : never
type MixedParser<T> = T extends AcceptedParserPrimitives ? GetParser<keyof ParserMap & T> : never
type PrimitiveTypeMap = {
string: 'string'
number: 'number'
boolean: 'boolean'
Date: 'Date'
object: 'object'
}

// Ensure PrimitiveTypeName returns only valid keys of ParserMap
type PrimitiveTypeName<T extends AcceptedParserPrimitives> = T extends keyof PrimitiveTypeMap
? PrimitiveTypeMap[T]
: never

// Now, define the GetParser type function that retrieves the correct parser based on T
type GetParser<T extends AcceptedParserPrimitives> = T extends (infer U)[]
? Parser<U[]>
: PrimitiveTypeName<T> extends keyof ParserMap
? ParserMap[PrimitiveTypeName<T>] extends Parser<infer U>
? Parser<U>
: never
: never

type MixedParser<T extends AcceptedParserPrimitives> = GetParser<T>

export const array = <T extends AcceptedParserPrimitives>(
schema: MaybeArray<MixedParser<T>>,
Expand All @@ -34,11 +55,6 @@ export const array = <T extends AcceptedParserPrimitives>(
): Parser<T[]> => {
const _schema = Array.isArray(schema) ? schema : [schema]

assert(
Array.isArray(_schema),
new TypeError(message?.type_error || ERROR_CODES.ERR_VAL_8000.message()),
)

return {
name: 'array' as const,
parse: (value): T[] => {
Expand All @@ -49,18 +65,14 @@ export const array = <T extends AcceptedParserPrimitives>(

validateModifiers(value, modifiers)

// return value.reduce((result: T[], item: unknown, index: number) => {
// const parser = _schema[index % _schema.length]
// const parsedItem = parser.parse(item as any)
// validateModifiers([parsedItem], [modifiers[index % modifiers.length]])
// result.push(parsedItem)
// return result
// }, [])

return value.reduce((result: T[], item: unknown) => {
_schema.forEach((s) => result.push(s.parse(item)))
return result
// Use reduce to ensure the type is correctly inferred
const result: T[] = value.reduce((acc: unknown[], item: AcceptedParserPrimitives, index) => {
const parser = _schema[index % _schema.length] // Handle cyclic schema application
acc.push(parser.parse(item))
return acc
}, [])

return result
},
}
}

0 comments on commit 6bb5b77

Please sign in to comment.