Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow creating tuples with unlimited types #441

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

ForbesLindesay
Copy link

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

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.
@Project-Magenta
Copy link

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

@ForbesLindesay
Copy link
Author

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.

@gcanti
Copy link
Owner

gcanti commented Apr 11, 2020

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

@Project-Magenta
Copy link

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

@pyldin601
Copy link

Hey, any updates here?

@ForbesLindesay
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Question: How to make a tuple with more than 5 types?
4 participants