【发布时间】:2021-07-08 19:04:16
【问题描述】:
我在类中使用泛型时遇到问题。有一个类 Item 接受泛型 T 扩展约束 ItemValue 类型,还有一个类型 Items 包含 Item 的实例类型为 Item<ItemValue>。
问题在于编译器没有通过ItemValue 约束传递一个潜在有效的泛型参数,因为Item 的callback 属性将其用作回调值。
如果我从类中删除了callback 属性,则不会出现错误。
此外,我试图在没有类的情况下复制它,并且没有这样的错误。你认为这是一个错误,还是我做错了什么?
type ItemValue = number | string;
type Callback<T> = (value: T) => void;
class Item<T extends ItemValue> {
private value: T;
// If you comment this out, there will be no error
private callback: Callback<T> = () => { }
constructor(value: T) {
this.value = value;
}
}
type Items = {
[index: string]: Item<ItemValue>
};
let items: Items = {
a: new Item<string>('') // error
}
// Type 'Item<string>' is not assignable to type 'Item<ItemValue>'.
// Types of property 'callback' are incompatible.
// Type 'Callback<string>' is not assignable to type 'Callback<ItemValue>'.
// Type 'ItemValue' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.
// This will also result in a similar error
// type AnItem = Item<ItemValue>;
// let a: AnItem = new Item<string>('');
// Here trying to do the same without a class.
function addCallback<T extends ItemValue>(cb: Callback<T>) {
}
function prepareAddCallback(cb: Callback<string>) {
// No problems with putting Callback<string> to Callback<ItemValue>
// Is it a bug?
addCallback(cb);
}
更新:
正如@Joey 在他的回答中指出的那样:
string可分配给string | number,但(val: string) => void不可分配给(val: string | number) => void
type CallbackStrOrNum = (value: string | number) => void;
const addCallback = (cb: CallbackStrOrNum) => { };
addCallback((value: string) => { }); // error
let x: string | number = ''; // ok
这缩小了问题的范围。我现在的问题是,为什么会这样?
更新 2
为了清楚起见,我通过定义 private callback: Callback<ItemValue> = () => { } 而不是 private callback: Callback<T> = () => { } 解决了这个示例中的问题,在回调参数中使用泛型在这里并不重要。这里的教训是不要定义具有泛型的函数类型属性,因为这样该类将是不可扩展的,例如Item<number> 不能分配给 Item<string | number>
此外,在实际示例中,它是一个回调字典,以防您想知道为什么我没有将 callback 定义为常规方法。
【问题讨论】:
标签: javascript typescript typescript-typings typescript-generics