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

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]>
playground
reference:
Odd Number Type
["a", 1, "b"]okay or not okay?