typescript 索引为奇数或偶数时具有不同类型的数组

8ehkhllq  于 2022-12-24  发布在  TypeScript
关注(0)|答案(3)|浏览(227)

我正在寻找一个类型OddEvenArray<Odd,Even>,它可以做以下事情类型安全为OddEvenArray<string,number>["a",1,"b",2].
我不知道在打字时如何区分奇数和偶数索引。
PS:很抱歉,但是我正在处理的JSON看起来是这样的^^'

vs91vp4v

vs91vp4v1#

数组索引是number类型,数字类型可以是任何数字(如number)或特定数字(如1 | 2 | 47)。
在类型级别上没有其他选项,这意味着从Typescript 4.9开始,类似的东西不可能被注解。

mepcadol

mepcadol2#

你不能用 typescript 做到这一点。我希望你能。这将是一个很酷的语言功能。
最接近于“偶数”类型的东西看起来像下面这样。把它 Package 在一个类中。对偶数做同样的事情。解决扭结。

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

o3imoua43#

这只能用泛型函数实现,不能直接将此类型赋给变量,必须用函数检查
这只适用于元组,不适用于数组

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

运动场
这种方法的问题在于,它不支持超过1000的元组长度,因为IsStringAndOddTuplemax递归仅为1000
我相信有一个 meta解决方案可以超越这个限制,但工作太多了
即使如此,元组长度也不能超过10,000,因为元组的最大长度是10,000
还有另一种更具伸缩性的方法,但这需要重新构建元组
//===========更新==============
我找到了一种不递归循环元组的方法,现在它可以超过1000的长度,并且只受OddNumbers的数量限制,仍然受元组的最大长度(10,000)的限制。
这意味着现在它支持最大长度为1997的数字,除非我们找到一种更好的方法来生成最大为10,000的所有奇数,或者您可以手动完成

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
参考:
Odd Number Type

相关问题