src/types/tuple.js
// @flow
const { getType } = require('../utils')
const { validatorError } = require('../error')
const { isEmpty } = require('../is')
import type { TypeValidator } from '../'
type V<T> = TypeValidator<T>
type TupleT =
(<A>(V<A>) => TypeValidator<[A]>)
& (<A, B>(V<A>, V<B>) => TypeValidator<[A, B]>)
& (<A, B, C>(V<A>, V<B>, V<C>) => TypeValidator<[A, B, C]>)
& (<A, B, C, D>(V<A>, V<B>, V<C>, V<D>) => TypeValidator<[A, B, C, D]>)
& (<A, B, C, D, E>(V<A>, V<B>, V<C>, V<D>, V<E>) => TypeValidator<[A, B, C, D, E]>)
& (<A, B, C, D, E, F>(V<A>, V<B>, V<C>, V<D>, V<E>, V<F>) => TypeValidator<[A, B, C, D, E, F]>)
& (<A, B, C, D, E, F, G>(V<A>, V<B>, V<C>, V<D>, V<E>, V<F>, V<G>) => TypeValidator<[A, B, C, D, E, F, G]>)
& (<A, B, C, D, E, F, G, H>(V<A>, V<B>, V<C>, V<D>, V<E>, V<F>, V<G>, V<H>) => TypeValidator<[A, B, C, D, E, F, G, H]>)
& (<A, B, C, D, E, F, G, H, I>(V<A>, V<B>, V<C>, V<D>, V<E>, V<F>, V<G>, V<H>, V<I>) => TypeValidator<[A, B, C, D, E, F, G, H, I]>)
& (<A, B, C, D, E, F, G, H, I, J>(V<A>, V<B>, V<C>, V<D>, V<E>, V<F>, V<G>, V<H>, V<I>, V<J>) => TypeValidator<[A, B, C, D, E, F, G, H, I, J]>)
function tupleOf_ (...typeFuncs) {
function tuple (value: mixed, _scope = '') {
const cardinality = typeFuncs.length
if (isEmpty(value)) return typeFuncs.map(fn => fn(value))
if (Array.isArray(value) && value.length === cardinality) {
const tupleValue = []
for (let i = 0; i < cardinality; i += 1) {
tupleValue.push(typeFuncs[i](value[i], _scope))
}
return tupleValue
}
throw validatorError(tuple, value, _scope)
}
tuple.type = () => `[${typeFuncs.map(fn => getType(fn)).join(', ')}]`
return tuple
}
// $FlowFixMe - $Tuple<(A, B, C, ...)[]>
const tupleOf: TupleT = tupleOf_
exports.tupleOf = tupleOf