Bug报告
我正在使用 solid-js
npm 包,它定义了一个名为 Setter
的类型:
type Setter<T> = (undefined extends T ? () => undefined : {}) & (<U extends T>(value: (prev: T) => U) => U) & (<U extends T>(value: Exclude<U, Function>) => U) & (<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)) => U);
我不太理解其中的逻辑,但它给我带来了一些问题:
type Setter<T> = (undefined extends T ? () => undefined : {}) & (<U extends T>(value: (prev: T) => U) => U) & (<U extends T>(value: Exclude<U, Function>) => U) & (<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)) => U);
class A { a = 1 }
class B extends A { b = 2 }
type Test<T> = { 0: Setter<T> };
declare const a: Test<A>;
const b: Test<B> = a; // ERROR!
我创建了一个具有属性 0
的对象,该属性包含一个 Setter
,似乎它不是协变的。
检查错误时,看起来问题起源于这部分 undefined extends T ? () => undefined : {}
,实际上,如果我删除它,这就可以工作了,而且即使这是类型的唯一部分,问题仍然会发生:
type Setter<T> = undefined extends T ? () => undefined : {};
class A { a = 1 }
class B extends A { b = 2 }
type Test<T> = { 0: Setter<T> };
declare const a: Test<A>;
const b: Test<B> = a; // ERROR!
我认为这是一个错误,因为类型是相同的:
type TA = Test<A>;
// ^? type TA = { 0: {}; }
type TB = Test<B>;
// ^? type TB = { 0: {}; }
此外,如果将 Test
定义为 [ Setter<T> ]
,则不会发生错误:
type Setter<T> = undefined extends T ? () => undefined : {};
class A { a = 1 }
class B extends A { b = 2 }
type Test<T> = [ Setter<T> ];
declare const a: Test<A>;
const b: Test<B> = a; // OK?!?!
🔎 搜索词
- undefined extends T
- 协变性
- 协变
🕗 版本与回归信息
此更改发生在版本 3.3.3 和 3.5.1 之间。(在所有版本中都不会发生的唯一Playground版本是 3.3.3)
⏯ Playground链接
Playground链接
💻 代码
type Setter<T> = (undefined extends T ? () => undefined : {}) & (<U extends T>(value: (prev: T) => U) => U) & (<U extends T>(value: Exclude<U, Function>) => U) & (<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)) => U);
// type Setter<T> = (<U extends T>(value: (prev: T) => U) => U) & (<U extends T>(value: Exclude<U, Function>) => U) & (<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)) => U);
// type Setter<T> = undefined extends T ? () => undefined : {};
class A { a = 1 }
class B extends A { b = 2 }
type Test<T> = { 0: Setter<T> };
// type Test<T> = [ Setter<T> ];
declare const a: Test<A>;
const b: Test<B> = a; // ERROR!
type TA = Test<A>;
// ^?
type TB = Test<B>;
// ^?
🙁 实际行为
无法将 b
的值分配给 a
。
至少它是错误的,因为它不一致。
🙂 预期行为
可以将 b
的值分配给 a
3条答案
按热度按时间6g8kf2rb1#
我相信这里的错误是我们没有将
U extends T
标记为在T
上不可测量的方差计算。cc @ahejlsberg
jaxagkaj2#
我之前以为我已经有一个PR来修复这个问题了。:P
svmlkihl3#
由于#43887从未被合并,#54866是否会解决这个问题?