Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array with different type when index is odd or even

Tags:

typescript

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 ^^'

like image 689
Florian Reisinger Avatar asked Sep 16 '26 17:09

Florian Reisinger


1 Answers

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

like image 122
Acid Coder Avatar answered Sep 18 '26 16:09

Acid Coder