如何在元组中重用剩余类型?

How to reuse rest types in tuples?

function A<
    NumArr extends [] | number[],
    BoolArr extends [] | boolean[],
    Params extends [...NumArr, "middle-element", ...BoolArr] = [...NumArr, "middle-element", ...BoolArr]
>(...arr: Params): Params {
    return arr
}

//not a single error
const
    test1: [1, false] = A(1, false),
    test2: [false, "middle-element", 2] = A(false, "middle-element", 2),
    test3: [] = A()

如何让TS检测Params中元素的顺序是否符合要求? 或者只是解释为什么这段代码不符合直觉逻辑。

对于 TypeScript 来说,这不是一项简单的任务。休息参数不以您期望的方式工作后的休息参数。事实上,论点只是推断出来的,并没有得到验证。不幸的是,您应该自己编写验证逻辑。

进入正题。

考虑这个例子:

type Elem = number | boolean | "middle-element";

type Last<T extends any[]> = T extends [infer _]
  ? never
  : T extends [...infer _, infer Tl]
  ? Tl
  : never

type HandleEmpty<T extends any[], Data> = T['length'] extends 0 ? never : Data

type Validation<Params extends any[], Cache extends Elem[] = []> =
  Params extends []
  ? Cache['length'] extends 0
  ? never
  : Cache
  : Params extends [infer Fst, ...infer Rest]
  ? Cache extends []
  ? Fst extends number
  ? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
  : never
  : Fst extends number
  ? Last<Cache> extends number
  ? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
  : never
  : Fst extends "middle-element"
  ? Last<Cache> extends number
  ? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
  : never
  : "middle-element" extends Cache[number]
  ? Fst extends boolean
  ? Validation<Rest, [...Cache, Fst]>
  : never
  : never
  : never

{
  type Test = Validation<[42, 43, "middle-element", false, true]> // ok
  type Test2 = Validation<[42, "middle-element", true, false]> // ok

  type Test3 = Validation<[false, "middle-element", 42]> // never
  type Test4 = Validation<[42, false]> // never
  type Test5 = Validation<[false, false, false, "middle-element", 42, "middle-element", 43]> //never
  type Test6 = Validation<[false, false, false, "middle-element", 42, false, 43]> // never
  type Test7 = Validation<[false, 42, "middle-element"]> // never
  type Test8 = Validation<[false, "middle-element", 42, false, "middle-element", 42,]> // never
  type Test9 = Validation<[false, "middle-element"]> // never
  type Test10 = Validation<[false]> // never
  type Test11 = Validation<[]> // never
  type Test12 = Validation<[42, "middle-element", boolean, "middle-element", 43]> //never
  type Test13 = Validation<[2, false, "middle-element"]> // never
}

type IsNever<T> = [T] extends [never] ? true : false;

function check<
  Params extends Elem[],
  IsValid extends Validation<Params>
>(...arr: IsNever<IsValid> extends true ? [never] : [...Params]) {
  return arr
}

/**
 * Ok
 */
const valid = check(1, 'middle-element', false)
const valid2 = check(1, 42, 43, 67, 'middle-element', false, true, false)

/**
 * Errors
 */
const test2 = check(false, "middle-element", 2)
const test1 = check(1, false)
const test3 = check()

我了解 Validation 实用程序类型根本不可读。

这里有 js 表示。请把它当作一个解释。我不知道这段代码在tuntime中是否可以:

const last = (data: any) => data[data.length - 1]

const handleEmpty = (data: any[], defaultValue) => data.length === 0 ? null : defaultValue

const never = null;

const validation = (params: any[], cache: any[] = []): any[] | null => {
  if (params.length === 0 && cache.length === 0) {
    return never // never is null
  }
  const [fst, ...rest] = params;
  if (cache.length === 0) {
    if (typeof fst === 'number') {
      return handleEmpty(rest, validation(rest, [...cache, fst]))
    } else {
      return never
    }
  }
  if (typeof fst === 'number') {
    return handleEmpty(rest, validation(rest, [...cache, fst]))
  }
  if (typeof fst === "middle-element") {
    if (typeof last(cache) === 'number') {
      return handleEmpty(rest, validation(rest, [...cache, fst]))

    }
    return null
  }
  if (cache.includes('middle-element')) {
    if (typeof fst === 'boolean') {
      return handleEmpty(rest, validation(rest, [...cache, fst]))
    }
  }
  return never
}

正如您可能已经注意到的那样,有很多 if 条件语句,但它非常简单且合乎逻辑。

我还包括了几个 Validation 实用程序类型的测试。你可以写更多。由你决定。

如果您想了解更多关于 typescript 验证的信息,请查看我的博客 here and here