首页 > 解决方案 > 从只读元组类型中过滤掉值

问题描述

我在编写一个辅助类型时遇到了一些麻烦,它接受一个元组Parser<T>作为参数并返回一个Ts 的元组类型,除了 when Tis undefined

这是我到目前为止所拥有的:

class Parser<T> {}

type ToSequenceValueType<P extends ReadonlyArray<Parser<any>>> =
    P extends [infer P, ...infer R]
    ? P extends Parser<infer V>
      ? V extends undefined
        ? ToSequenceValueType<R>
        : [V, ...ToSequenceValueType<R>]
      : never
    : []

type A = readonly [Parser<number>, Parser<string>, Parser<undefined>, Parser<boolean>]

type R = ToSequenceValueType<A> // Should be [number, string, boolean]

但是递归调用 ( ToSequenceValueType<R>) 被下划线标记为错误,它显示:

Type 'R' does not satisfy the constraint 'readonly Parser<any>[]'

我应该怎么做 ?

链接到游乐场

标签: typescript

解决方案


我相信你正在寻找这个解决方案:

class Parser<T> { }

/**
 * I'm using square brackets for [Val] to avoid distributivity
 */
type MapPredicate<T> =
  T extends Parser<infer Val>
  ? [Val] extends [undefined]
  ? []
  : [Val]
  : never;

type Mapped<
  Arr extends ReadonlyArray<Parser<any>>,
  Cache extends ReadonlyArray<unknown> = readonly []
  > =
  /**
   * If argument is empty array - return empty array
   */
  Arr extends readonly []
  ? readonly []
  /**
   * This should be the last call of recursion
   * I just adding last element of an array to Cache
   */
  : Arr extends readonly [infer H]
  ? [...Cache, ...MapPredicate<H>]
  /**
   * If array contains more than one element
   * I call Mapped with Tail (all elements but the first)
   * an adding first element (Head) to cache
   */
  : Arr extends readonly [infer Head, ...infer Tail]
  ? Tail extends ReadonlyArray<Parser<any>>
  ? Mapped<[...Tail], [...Cache, ...MapPredicate<Head>]>
  : never
  : Cache;


type P = Parser<number>;


type A = readonly [Parser<number>, Parser<string>, Parser<undefined>, Parser<boolean>]

type R = Mapped<A> // [number, string, boolean]

因为您想ToSequenceValueType递归调用 ->P并不总是会扩展[infer P, ...infer R],所以最后两次调用它将扩展空数组和带有一个元素的数组。

您可以在我的博客中找到有关元组的更多信息/解释和示例

操场

如果MapPredicate<H>返回空数组[]...MapPredicate<H>则计算结果为空,这就是我过滤undefined值的方式


推荐阅读