io-ts
io-ts copied to clipboard
feat: allow creating tuples with unlimited types
This change is backwards compatible. For TypeScript versions < 3.8, you can stil create tuples up to 5 entries long, but for TypeScript versions >= 3.8 you can create tuples of unlimited length, thanks to the fact that they properly support mapped types on arrays.
I had some difficulty getting the dtslint tests to work due to the forked dtslint implementation, hence there being a lot of files that moved around there.
Closes #431
the tests are broken here is what they should contain:
import * as t from '../../../src'
const Tuple8 = t.tuple([t.string, t.string, t.string, t.string, t.string, t.string])
type Tuple8TypeTest = t.TypeOf<typeof Tuple8> // $ExpectType [string, string, string, string, string, string]
type Tuple8OutputTest = t.OutputOf<typeof Tuple8> // $ExpectType [string, string, string, string, string, string]
const Tuple9 = t.tuple([t.string, t.string, t.boolean, t.string, t.string, t.string, t.string])
type Tuple9TypeTest = t.TypeOf<typeof Tuple9> // $ExpectType [string, string, boolean, string, string, string, string]
type Tuple9OutputTest = t.OutputOf<typeof Tuple9> // $ExpectType [string, string, boolean, string, string, string, string]```
Thanks, I've fixed the test case. This version doesn't require the as const
, but the example I posted as a temporary workaround in #431 does for now.
@ForbesLindesay thanks for this PR.
This change is backwards compatible
Actually this is a breaking change, the following example will break
// v----------v--------explicit type annotation
const T = t.tuple<t.StringC, t.NumberC>([t.string, t.number])
I know this is a contrived example but is a breaking change nonetheless.
For a backwards compatible change we could just add an additional overloading:
// refactored ---v
export interface TupleC<CS extends [Mixed, ...Array<Mixed>]>
extends TupleType<
CS,
{ [K in keyof CS]: CS[K] extends Mixed ? TypeOf<CS[K]> : unknown },
{ [K in keyof CS]: CS[K] extends Mixed ? OutputOf<CS[K]> : unknown },
unknown
> {}
/**
* @since 1.0.0
*/
export function tuple<A extends Mixed, B extends Mixed, C extends Mixed, D extends Mixed, E extends Mixed>(
codecs: [A, B, C, D, E],
name?: string
): TupleC<[A, B, C, D, E]>
export function tuple<A extends Mixed, B extends Mixed, C extends Mixed, D extends Mixed>(
codecs: [A, B, C, D],
name?: string
): TupleC<[A, B, C, D]>
export function tuple<A extends Mixed, B extends Mixed, C extends Mixed>(
codecs: [A, B, C],
name?: string
): TupleC<[A, B, C]>
export function tuple<A extends Mixed, B extends Mixed>(codecs: [A, B], name?: string): TupleC<[A, B]>
export function tuple<A extends Mixed>(codecs: [A], name?: string): TupleC<[A]>
// new overloading ---v
export function tuple<CS extends [Mixed, ...Array<Mixed>]>(codecs: CS, name?: string): TupleC<CS>
export function tuple<CS extends [Mixed, ...Array<Mixed>]>(
codecs: CS,
name: string = `[${codecs.map((type) => type.name).join(', ')}]`
): TupleC<CS> {
// ...implementation
}
for TypeScript versions >= 3.8 you can create tuples of unlimited length, thanks to the fact that they properly support mapped types on arrays
AFAIK mapped tuples are supported in version 3.5+. The change above seems to work fine in dtslint tests, could you please double check?
hmm... the tests seem to work on all versions 3.5+ @ForbesLindesay can you confirm?
Hey, any updates here?
I ended up creating my own validation(/parsing) library for TypeScript as I found issues with all existing libraries. You might want to try out funtypes if you've been frustrated by this/similar issue(s).