typescript - 类型 'Observable' 不能赋值给类型 'Observable'
我们正在使用 Knockout.js (v3.5.0) 及其 TypeScript 定义。它们在 TypeScript 4.6.2 之前工作正常。然而,问题似乎比定义文件中的情况“更深”。似乎 TypeScript 在处理布尔类型时有所变化。因此,我没有将这个问题标记为 Knockout.js 问题,而是创建了一个受 Knockout d.ts 启发的小示例代码来说明这个问题:
interface Observable<T>
{
(): T;
(value: T): any;
}
function observable<T>(value: T): Observable<T>
{
return undefined as any; // the implementation is not important
}
const x: Observable<boolean> = observable(false);
这段代码有一个编译问题:
Type 'Observable<false>' is not assignable to type 'Observable<boolean>'.
Types of parameters 'value' and 'value' are incompatible.
Type 'boolean' is not assignable to type 'false'.
当然,将 false 强制转换为 boolean 是可行的,但我认为这是一种变通方法,而不是解决方案(显然我们需要对每个 true/false 的出现都进行转换)。有没有办法真正解决这个问题?
编辑:根据评论,很明显某些类型检查已被更改。更多示例可以在这里看到。游乐场链接。
有关于此更改的任何信息(附解释)吗?
编辑2:按照评论中的建议,我在 https://github.com/microsoft/TypeScript/issues/48150 提交了一个错误报告
答案#1
我建议改为明确指定泛型类型,如:
const x = observable<boolean>(false);
原因是我们正在假设false意味着boolean。通常确实如此,但并非总是。比如想象这些类型
const x = observable<false | undefined>(false);
const y = observable(false);
(对于任何试图以其他方式解决打字问题的人,请确保上述内容也是有效的。)
答案#2
根据回复了 Github 问题(https://github.com/microsoft/TypeScript/issues/48150)的用户,Typescript 4.6 的编译错误是预期的:
我相信这是一个在旧版本中未被正确处理的正确错误。泛型参数 T 是不变的,因为它既用于协变位置 (() => T),也用于逆变位置 ((value: T) => any)。
这确实是真的。既然用户帮助解决了问题,为了完整起见,我将尝试在这里重新表述并总结他的评论。
第一个提出的解决方案只能部分解决问题:
function observable<T>(value: T extends infer U ? U: never): Observable<T>
{
return undefined as any; // the implementation is not important
}
const x: Observable<boolean> = observable(false); // no error
然而,如果没有类型注解,这将产生 unknown 类型。
const bad = observable(false);
// ^ unknown, which should be Observable<boolean>
正确的解决方案似乎是引入另一个类型参数
declare function observable<T, U = any>(value?: T extends infer R ? R : U):
unknown extends T ? Observable<U> : Observable<T>
游乐场链接
由于主要问题出在 Knockout.js 库上,我在那儿提交了问题(https://github.com/knockout/knockout/issues/2589),希望有足够 TypeScript 知识的人能解决这个问题。
