Skip to content

Instantly share code, notes, and snippets.

@itsMapleLeaf
Created March 15, 2020 04:55
Show Gist options
  • Select an option

  • Save itsMapleLeaf/0aaee24dd8cd440962246fb85457aeb9 to your computer and use it in GitHub Desktop.

Select an option

Save itsMapleLeaf/0aaee24dd8cd440962246fb85457aeb9 to your computer and use it in GitHub Desktop.
type Validator<T = unknown> = {
parse: (value: unknown) => T
is: (value: unknown) => value is T
}
type ValidatorType<V> = V extends Validator<infer T> ? T : never
type ValueOf<T> = T extends readonly (infer V)[] ? V : T[keyof T]
const raise = (error: string): never => {
throw new Error(error)
}
const createValidator = <T,>(
isValid: (value: unknown) => value is T,
errorMessage: string,
): Validator<T> => ({
is: isValid,
parse: arg => (isValid(arg) ? arg : raise(errorMessage)),
})
export const string = createValidator(
(value): value is string => typeof value === 'string',
'value is not a string',
)
export const number = createValidator(
(value): value is number => typeof value === 'number',
'value is not a number',
)
export const boolean = createValidator(
(value): value is boolean => typeof value === 'boolean',
'value is not a boolean',
)
export const union = <T extends Validator[]>(...memberTypes: T) =>
createValidator(
(value): value is ValidatorType<ValueOf<T>> => memberTypes.some(type => type.is(value)),
'union check failed',
)
export const array = <T,>(itemType: Validator<T>) =>
createValidator(
(value): value is T[] =>
Array.isArray(value) && value.every(item => itemType.is(item)),
'expected array, received otherwise',
)
export const literal = <T,>(value: T) =>
createValidator((arg): arg is T => arg === value, 'literal check failed')
declare const unsafeValue: unknown
const test = union(string, array(number))
const value = test.parse(unsafeValue)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment