3

I am looking for a type OddEvenArray<Odd,Even>, which can do the following thing typesafe as OddEvenArray<string,number>: ["a",1,"b",2].

I have no idea to distinguish between odd and even index during typing.

PS: I am sorry, but the JSON I am dealing with looks like that ^^'

5
  • There's no specific type that works this way but you could come up with a generic constraint that does. But must the array be of even length or can it end in the odd one? Like, is ["a", 1, "b"] okay or not okay? Commented Dec 22, 2022 at 20:14
  • 1
    Assuming it must be of even length, then this approach might meet your needs. Does it? If so I could write up an answer explaining; if not, what specific use case is unmet? Commented Dec 22, 2022 at 20:22
  • @jcalz: Its always of even length :) Commented Dec 23, 2022 at 12:17
  • @jcalz: That would be extreamly helpful if you could provide this as answer. This seems like the solution for me Commented Dec 23, 2022 at 12:19
  • 1
    Looks like AcidCoder's answer is similar so I won't write anything up here unless you tell me it's preferable to the other one. Good luck! Commented Dec 23, 2022 at 16:00

3 Answers 3

2

this is only possible with function generic, you cannot directly assign this type to a variable, you must check with function

this only works for tuple, not array

type Odd<
    X extends number,
    Y extends unknown[] = [1],
    Z extends number = never
> = Y['length'] extends X
    ? Z | Y['length']
    : Odd<X, [1, 1, ...Y], Z | Y['length']>

type OddNumbers = Odd<1999> // 1 | 3 | 5 | 7 | ....1997

type IsStringAndOddTuple<T extends unknown[], ACC extends any[]=[]> = 
    T extends [infer A, ...infer J] 
        ? T['length'] extends OddNumbers 
            ? IsStringAndOddTuple<J,[...ACC, A extends number? A : "expect number type at even index" ]>
            : IsStringAndOddTuple<J,[...ACC, A extends string? A : "expect string type at Odd index" ]>
        :ACC

const isStringAndOddTuple =<T extends unknown[]>(tuple: T extends never? T : IsStringAndOddTuple<T>)=>{
  // don't neeed anything here
}

type C = IsStringAndOddTuple<[1, 2, 3, 4]>
//   ^?

type D = IsStringAndOddTuple<["a","b","c","d"]>
//   ^?

type E = IsStringAndOddTuple<["a",1,"b",2]>
//   ^?

isStringAndOddTuple([1, 2, 3, 4]) 
isStringAndOddTuple(["a","b","c","d"]) 
isStringAndOddTuple<["a",1,"b",2]> 

enter image description here

playground

the problem with this method is, it does not support tuple length over 1000 because IsStringAndOddTuple max recursion is only 1000

I believe there is a meta solution that can exceed this limitation, but the works are just too much

even so you tuple length cannot exceed 10,000 because max length of a tuple is 10,000

there is another more scalable method, but that requires you to rebuild the tuple

//============UPDATE================
I found a way to loop the tuple without recursion, now it can exceeds length 1000 and limit only by the number of OddNumbers, still bounded by the max length of tuple(10,000)

which mean now it supports length up to 1997, unless we found a better way to generate all odd numbers up to 10,000, or you could just do it manually


type Odd<
    X extends number,
    Y extends unknown[] = [1],
    Z extends number = never
> = Y['length'] extends X
    ? Z | Y['length']
    : Odd<X, [1, 1, ...Y], Z | Y['length']>

type OddNumbers = Odd<1999> // 1 | 3 | 5 | 7 | ....1997

type IsOddStringAndEvenNumberTuple<T extends unknown[]> = T extends [infer S, ...infer R] ? { [K in keyof [S, ...R]]: K extends `${OddNumbers}`
    ? T[K] extends number ? T[K] : "expect number type at even index"
    : T[K] extends string ? T[K] : "expect string type at Odd index" }
    : never

const isStringAndOddTuple = <T extends unknown[]>(tuple: T extends never ? T : IsOddStringAndEvenNumberTuple<T>) => {
    // don't neeed anything here
}

type C = IsOddStringAndEvenNumberTuple<[1, 2, 3, 4]>
//   ^?

type D = IsOddStringAndEvenNumberTuple<["a", "b", "c", "d"]>
//   ^?

type E = IsOddStringAndEvenNumberTuple<["a", 1, "b", 2]>
//   ^?

isStringAndOddTuple([1, 2, 3, 4])
isStringAndOddTuple(["a", "b", "c", "d"])
isStringAndOddTuple<["a", 1, "b", 2]> 

enter image description here playground

reference:
Odd Number Type

Sign up to request clarification or add additional context in comments.

Comments

1

An array index is a number type, and number types can either be any number (as number) or specific numbers (as 1 | 2 | 47).

There aren't really any other options at the type level. This means that something like this not possible to annotate as of Typescript 4.9.

Comments

0

You cannot do that with Typescript. I wish you could. It would be a cool language feature.

The closest thing to an "even number" type would look something like the following. Wrap it in a class. Do the same thing with even numbers. Work out the kinks.

class EvenNumber {
  public constructor(n: number) {
    if (n % 2 != 0) {
      throw new Error("argument is not even:", n);
    }
    this.num = n;
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.