打字稿:推断类型的一般要求

时间:2020-04-08 19:13:31

标签: typescript generics type-inference

问题

您如何推断泛型类的泛型要求(扩展部分中的内容)?

说明

// UserGivenClassThatCouldHaveAnyGeneric
class A<T extends string> {
  constructor(a: T) {}
}

我如何推断通用T必须扩展string。我需要在条件声明中提供此信息。

我尝试了以下

type E<W> = any extends A<infer T> ? W extends T ? A<W> : void : void

E在给定W不扩展T要求的情况下应该为空,但在给定from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Firefox() driver.get("http://somedomain/url_that_delays_loading") try: element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")) ) finally: driver.quit() 的情况下应为A。但是,即使没有显示语法错误警告,这也根本不起作用。

1 个答案:

答案 0 :(得分:1)

我的建议是将E<W>更改为以下内容:

type E<W> = never extends A<infer T> ? [W] extends [T] ? A<W> : void : never

首先,大多数类型any的条件类型(其中选中的类型为any extends X ? Y : Z,例如Y | Z,最终将被视为联合X。也就是说,any在特殊情况下可以接受条件类型的两个分支。有关此问题的讨论,请参见microsoft/TypeScript#27418。假设您仅尝试使用条件类型的true分支,那么最好使用never extends X ? Y : Z。通常,never extends X将始终为true,然后结果将为Y。另外,如果您不想担心工会混乱,可以将其设置为never,而不是void。类型A | never的计算结果为A,而A | void的计算结果通常不是。

因此,我们将type E<W> = any extends A<infer T> ? W extends T ? A<W> : void : void更改为type E<W> = never extends A<infer T> ? W extends T ? A<W> : void : never


现在剩下的问题是:如果W本身是联合类型,您想做什么?如果您将E<W>定义为W extends T而不是[W] extends [T],它将被视为distributive conditional type。这意味着,如果W是类似于A | B | C的联合类型,则E<W>将评估该联合的每个成员的条件并将结果统一,从而产生等效结果E<A> | E<B> | E<C>中的。也许这就是您想要的,但可能不是。毕竟,如果Wstring | number,您可能想让void出来,而不是A<string> | void,对吗?

条件类型何时成为分布的规则是,您正在检查“裸”或“裸”通用类型参数。由于W是泛型类型参数,因此条件类型W extends T ? ...将是分布式的。关闭此行为的最简单方法是用一些协变变量“覆盖”类型参数,例如单元素元组类型。这样就变成了[W] extends [T] ? ...


好的,希望能有所帮助;祝你好运!

Playground link to code