简体   繁体   English

Typescript 自定义限制与 Generics

[英]Typescript custom restriction with Generics

While working on a library, I discovered what to me looks like a bug when using Generics:在开发库时,我发现在使用 Generics 时对我来说看起来像一个错误:

type R<A> = A extends Bottom ? A : A
type Bottom = { test: number }

const f = <A extends Bottom>(a: A) => {
    useIt(a) // type error here
}

const useIt = <A extends Bottom>(a: R<A>) => console.log(a)

As you can also see in the Playground example , for some unclear reason a cannot be used as R<A> , even though this type is equivalent to A .正如您在Playground 示例中看到的那样,由于某些不清楚的原因a不能用作R<A> ,即使此类型等价于A

The type error is:类型错误是:

Argument of type 'A' is not assignable to parameter of type 'R<A>'.
  Type 'Bottom' is not assignable to type 'R<A>'.

Using a concrete type instead of a generic will work as expected, eg:使用具体类型而不是泛型将按预期工作,例如:

type X = {test: 1}
const x: R<X> = {test: 1} // all good
const noX: R<X> = {test: 2} // error

Having a better restriction type will also work as expected for concrete types:对于具体类型,具有更好的限制类型也将按预期工作:

type R<A> = A extends Bottom ? A : never
const x: R<X> = {test: 1} // all good
const error: R<{}> = {} // type error as expected given that {} doesn't extend Bottom

So, is there any way to make it work with Generics?那么,有什么方法可以使它与 Generics 一起使用?

This is more of a design limitation than a bug;这更多的是设计限制而不是错误。 unresolved conditional types (ones which depend on a yet-to-be-specified generic type parameter) are more or less deferred completely by the compiler, and almost nothing is seen as assignable to them.未解析的条件类型(依赖于尚未指定的泛型类型参数的类型)或多或少被编译器完全延迟,几乎没有任何东西可以分配给它们。


There's an open issue, microsoft/TypeScript#23132 , that suggests using generic constraints to determine assignability to unresolved conditional types;有一个未解决的问题microsoft/TypeScript#23132建议使用泛型约束来确定对未解决的条件类型的可分配性; I think if this suggestion were implemented your example code would work (because A extends Bottom would be seen as true)... so you might want to go that issue and give it a and possibly explain your use case if you think it's more compelling than what's there.我认为如果实施此建议,您的示例代码将起作用(因为A extends Bottom将被视为正确)...因此您可能想要 go 该问题并给出它并可能解释您的用例如果您认为它更引人注目比那里的东西。

There's also microsoft/TypeScript#33912 , which proposes using control flow analysis to determine assignability to unresolved conditional types, which might also help if it were to be implemented.还有microsoft/TypeScript#33912 ,它建议使用控制流分析来确定对未解析条件类型的可分配性,如果要实现它也可能会有所帮助。


Right now I think the only way to "make it work" is either to use type assertions , as in:现在我认为“让它工作”的唯一方法是使用type assertions ,如:

useIt(a as R<A>)

or to express your type so that it is no longer an unresolved conditional type, if possible;或表达您的类型,使其不再是未解决的条件类型,如果可能的话; in your example code, R<A> is unconditionally A , so在您的示例代码中, R<A>是无条件A ,所以

// type R<A> = A extends Bottom ? A : A
type R<A> = A

would solve it.会解决它。

Actually I see you changed R<A> in another part of your code to be essentially Extract<A, Bottom> .实际上,我看到您将代码的另一部分中的R<A>更改为本质上是Extract<A, Bottom> In some instances, Extract<T, U> can be replaced by the intersection T & U without ill effects;在某些情况下, Extract<T, U>可以替换为交集T & U而不会产生不良影响; you might try that instead:你可以试试:

// type R<A> = A extends Bottom ? A : never
type R<A> = A & Bottom

That might also work.这也可能奏效。


Okay, hope that helps;好的,希望有帮助; good luck!祝你好运!

Link to code 链接到代码

After a lot of tinkering, I solved this problem by explicitly adding the restriction:经过大量修改后,我通过显式添加限制解决了这个问题:

const f = <A extends Bottom>(a: R<A>) => {
    useIt(a) // works
}

const useIt = <A extends Bottom>(a: R<A>) => console.log(a)

Please note that now f argument has the same constraint of useIt , which will make the compiler happy.请注意,现在f参数具有与useIt相同的约束,这将使编译器满意。 With hindsight, this actually makes sense, so that we are 100% sure the type is usable for useIt too:)事后看来,这实际上是有道理的,因此我们 100% 确定该类型也可用于useIt :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM