【问题标题】:Array of generics泛型数组
【发布时间】:2019-08-10 15:49:41
【问题描述】:

我声明枚举及其转换器:

enum E { A, B };
type TRANSFORM<T extends E> = T extends E.A ? E.B : E.A;

并声明具有两个元素的数组类型,其中第二个是第一个元素的转换类型:

type qwe<T extends E> = [T, TRANSFORM<T>];

当我提供特殊的枚举元素时,它工作正常:

const element: qwe<E.A> = [E.A, E.A]; // Ok: Error: (Type 'E.A' is not assignable to type 'E.B')

如何声明这些元素的数组?我找到的唯一方法是:

const arr: (qwe<E.A> | qwe<E.B>)[] = [[E.A, E.A], [E.B, E.A]];
// Ok: Error: (Type '[E.A, E.A]' is not assignable to type '[E.A, E.B] | [E.B, E.A]')

但输入为

type b = qwe<E.A> | qwe<E.B>;

可能太大,当枚举E 将包含更多元素。简而言之,我该怎么写?

我试图这样声明:

type b = qwe<E>;

但它没有按预期工作。例如这个数组是正确的:

const arr: qwe<E>[] = [[E.A, E.A], [E.B, E.A]];

【问题讨论】:

  • 它不是分布式的。您需要将其声明为arr: qwe&lt;E.A | E.B&gt; = [[E.A, E.B], [E.B, E.A]]
  • @AluanHaddad,当我使用 qwe&lt;E.A | E.B&gt;[] 时,在此数组中未找到错误:[[E.A, E.A], [E.B, E.A]]。它等于qwe&lt;E&gt;[]

标签: typescript typescript-typings


【解决方案1】:

在开始之前,我要将您的类型名称更改为更传统的名称(即,qweQweTRANSFORMTransform)。我还将Transform 更改为lookup type 而不是conditional type

type Transform<T extends E> = { [E.A]: E.B; [E.B]: E.A }[T];

此定义应评估为与您的预期用例相同的类型,(Transform&lt;E.A&gt;E.BTransform&lt;E.B&gt;E.ATransform&lt;E&gt;E),但编译器通常会有比泛型类型更容易推断查找类型。如果你愿意,你可以改回原来的定义,以下应该仍然有效。


因此,我在这里建议的解决方案是让您的 Qwe&lt;T&gt; 类型 distribute 超过联合操作,这样 Qwe&lt;A | B&gt; 将始终评估为 Qwe&lt;A&gt; | Qwe&lt;B&gt;。当T 是未解析的泛型类型参数时,TypeScript 允许您通过distributive conditional typesT extends U ? X : Y 的形式执行此操作。例如:

type Qwe<T extends E = E> = T extends any ? [T, Transform<T>] : never;

T extends any ? 部分看起来像一个空操作,但它具有防止Qwe&lt;E&gt; 评估为[E, E] 的重要作用...相反,它将根据您的需要变为[E.A, E.B] | [E.B, E.A]

我还添加了type parameter default,这样当您将类型写为Qwe 时,它将被解释为Qwe&lt;E&gt;...因为我想这是您最想使用的类型。

好的,让我们确保这能如您所愿:

const arr: Qwe[] = [[E.A, E.B], [E.B, E.A]]; // okay
const bad: Qwe[] = [[E.A, E.A]]; // error

我觉得不错。希望有帮助;祝你好运!

Link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-21
    • 2011-04-25
    • 1970-01-01
    • 2019-03-21
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    相关资源
    最近更新 更多