类型 'Observable<false>' 不可分配给类型 'Observable<boolean>'
Type 'Observable<false>' is not assignable to type 'Observable<boolean>'
我们正在使用 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
是可行的,但我确实认为这是 hack,而不是解决方案(显然我们需要对每次出现的 true/false 进行转换)。
有什么办法可以真正解决这个问题?
编辑:根据评论,很明显某些类型检查已更改。可以在此处查看更多示例。 Playground Link.
是否有关于此更改的任何信息(以及解释)?
Edit2:按照评论中的建议,我在 https://github.com/microsoft/TypeScript/issues/48150
提交了错误报告
根据 user who has responded to the Github issue (https://github.com/microsoft/TypeScript/issues/48150) 预计 Typescript 4.6 编译错误:
I believe this is a correct error which was not handled properly in old versions.
The generic parameter T is invariant as it is used in both a covariant position () => T and a contravariant position (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 知识的人可以解决该问题。
我建议改为显式指定通用类型,例如:
const x = observable<boolean>(false);
原因是我们假设 false
意味着boolean
。通常是这样,但并非总是如此。想象一下,例如这些类型
const x = observable<false | undefined>(false);
const y = observable(false);
(对于任何试图以任何其他方式解决打字问题的人,请确保以上几行也有效。)
我们正在使用 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
是可行的,但我确实认为这是 hack,而不是解决方案(显然我们需要对每次出现的 true/false 进行转换)。
有什么办法可以真正解决这个问题?
编辑:根据评论,很明显某些类型检查已更改。可以在此处查看更多示例。 Playground Link.
是否有关于此更改的任何信息(以及解释)?
Edit2:按照评论中的建议,我在 https://github.com/microsoft/TypeScript/issues/48150
提交了错误报告根据 user who has responded to the Github issue (https://github.com/microsoft/TypeScript/issues/48150) 预计 Typescript 4.6 编译错误:
I believe this is a correct error which was not handled properly in old versions. The generic parameter T is invariant as it is used in both a covariant position () => T and a contravariant position (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 知识的人可以解决该问题。
我建议改为显式指定通用类型,例如:
const x = observable<boolean>(false);
原因是我们假设 false
意味着boolean
。通常是这样,但并非总是如此。想象一下,例如这些类型
const x = observable<false | undefined>(false);
const y = observable(false);
(对于任何试图以任何其他方式解决打字问题的人,请确保以上几行也有效。)