在使用库时,我发现使用泛型时对我来说似乎是一个错误:
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)
您也可以在
Playground example,由于某些不清楚的原因,a
不能用作R<A>
,即使这种类型等效于A
。
类型错误是:
Argument of type 'A' is not assignable to parameter of type 'R<A>'.
Type 'Bottom' is not assignable to type 'R<A>'.
使用具体类型代替泛型将按预期工作,例如:
type X = {test: 1}
const x: R<X> = {test: 1} // all good
const noX: R<X> = {test: 2} // error
对于特定类型,具有更好的限制类型也可以正常工作:
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
那么,有什么方法可以使其与泛型一起使用?
答案 0 :(得分:1)
更多的是设计限制,而不是错误;未解决的条件类型(取决于尚未指定的泛型类型参数)或多或少地由编译器完全推迟,并且几乎没有东西可分配给它们。
有一个未解决的问题,microsoft/TypeScript#23132建议使用泛型约束来确定对未解决的条件类型的可分配性;我认为,如果实施了此建议,您的示例代码将起作用(因为A extends Bottom
被认为是正确的)...因此,您可能想要解决该问题并给它加上?,并在可能的情况下解释您的用例比那里的东西更具吸引力。
还有microsoft/TypeScript#33912,它建议使用控制流分析来确定对未解决的条件类型的可分配性,如果要实现它,这也可能会有所帮助。
现在,我认为“使其正常工作”的唯一方法是使用type assertions,如下所示:
useIt(a as R<A>)
或表示您的类型,以便尽可能不再是无法解析的条件类型;在您的示例代码中,R<A>
是无条件A
,因此
// type R<A> = A extends Bottom ? A : A
type R<A> = A
将解决它。
实际上,我看到您在代码的另一部分将R<A>
更改为本质上为Extract<A, Bottom>
。在某些情况下,Extract<T, U>
可以用交集T & U
代替,而不会产生不良影响;您可以尝试以下方法:
// type R<A> = A extends Bottom ? A : never
type R<A> = A & Bottom
这也可能有效。
好的,希望能有所帮助;祝你好运!
答案 1 :(得分:0)
经过大量修改,我通过显式添加限制来解决此问题:
const f = <A extends Bottom>(a: R<A>) => {
useIt(a) // works
}
const useIt = <A extends Bottom>(a: R<A>) => console.log(a)
请注意,现在f
参数具有与useIt
相同的约束,这将使编译器满意。事后看来,这实际上是有道理的,因此我们100%确信该类型也可用于useIt
:)