io-ts icon indicating copy to clipboard operation
io-ts copied to clipboard

feat: allow creating tuples with unlimited types

Open ForbesLindesay opened this issue 4 years ago • 6 comments

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

ForbesLindesay avatar Apr 09 '20 14:04 ForbesLindesay

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]```

Project-Magenta avatar Apr 10 '20 15:04 Project-Magenta

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 avatar Apr 10 '20 16:04 ForbesLindesay

@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?

gcanti avatar Apr 11 '20 07:04 gcanti

hmm... the tests seem to work on all versions 3.5+ @ForbesLindesay can you confirm?

Project-Magenta avatar Apr 16 '20 03:04 Project-Magenta

Hey, any updates here?

pyldin601 avatar Jun 08 '21 06:06 pyldin601

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).

ForbesLindesay avatar Sep 02 '22 01:09 ForbesLindesay