我遇到了在控制台上产生这些错误的问题。
Type 'WebFieldB' does not satisfy the constraint 'WebFieldA & WebFieldB'.
服务器生成了2个类,不应该更改。
class WebFieldA {
readonly Name: string;
readonly IsUpdatable: boolean;
}
class WebFieldB {
readonly Name: string;
}
这是我的代码:
interface IFieldInfo {
name: string;
isUpdatable: boolean;
}
class SomeField<T extends WebFieldA & WebFieldB> implements IFieldInfo {
field: T;
constructor(pField: T) {
this.field = pField;
}
get name(): string {
return this.field.Name;
};
get isUpdatable(): boolean {
return this.field.IsUpdatable || false;
}
}
let field1: IFieldInfo = new SomeField<WebFieldA>({Name: 'fieldA', IsUpdatable: false});
let field2: IFieldInfo = new SomeField<WebFieldB>({Name: 'fieldB'}); **// Here for WebFieldB is error**
let myCollection: Array<IFieldInfo> = [field1, field2];
我期待什么?
我希望有一个由{2}类型的对象构建的IFieldInfo
集合:WebFieldA
和WebFieldB
(WFB没有isUpdatable
属性!)。不幸的是,我只能修改我的代码,而不是WebFieldA
或WebFieldB
。
也许另一个想法,没有泛型的话?我不知道......
答案 0 :(得分:2)
正如@recursive建议的那样,您的输入字段将是WebFieldA
或一个WebFieldB
,而不是WebFieldA
和 a WebFieldB
。这意味着您应该使用WebFieldA | WebFieldB
而不是WebFieldA & WebFieldB
。
isUpdatable
的实施是一个问题,因为它假设IsUpdatable
上有this.field
字段。您可以使用合适的防护装置解决此问题。不要在@ recursive的答案中使用instanceof
,除非您只计划传递WebFieldA
和WebFieldB
的实际实例,而不是具有相同属性的对象。我看到你的示例代码使用的是普通对象,所以你不应该使用instanceof
。
我喜欢使用的一个类型保护是以下有用的功能(它可能应该在库中):
function hasKey<K extends string>(key: K, obj: any): obj is {[P in K]: any} {
return key in obj;
}
这只是确保一个对象有一个特定的键。然后你可以实现isUpdatable
而不会出现这样的错误:
get isUpdatable(): boolean {
return hasKey('IsUpdatable',this.field) ? this.field.IsUpdatable : false;
}
但这有点多了。让我们回避打字机问题。请注意,从结构上讲,WebFieldA | WebFieldB
非常类似于
interface SomeWebField {
readonly Name: string;
readonly IsUpdatable?: boolean; // optional
}
并注意到你根本没有使用泛型。您也可以将通用替换为SomeWebField
:
class SomeField implements IFieldInfo {
field: SomeWebField;
constructor(pField: SomeWebField) {
this.field = pField;
}
get name(): string {
return this.field.Name;
};
get isUpdatable(): boolean {
return this.field.IsUpdatable || false;
}
}
let field1: IFieldInfo = new SomeField({Name: 'fieldA', IsUpdatable: false});
let field2: IFieldInfo = new SomeField({Name: 'fieldB'});
let myCollection: Array<IFieldInfo> = [field1, field2];
假设您没有其他未提及的隐藏用例,上述内容应该满足您的需求而无需泛型。
希望有所帮助;祝你好运!
答案 1 :(得分:1)
我不确定这是否会实现您的最终目标,但如果您更改此代码,则可以编译代码。
class SomeField<T extends (WebFieldA | WebFieldB)> implements IFieldInfo {
// ....
get isUpdatable(): boolean {
return this.field instanceof WebFieldA && this.field.IsUpdatable;
}
}
我做了一些改变。首先,我使用|
代替&
来表示T
只需要扩展其中一个类,而不是两者。然后,我在isUpdatable
属性getter中添加了一个类型保护,以确保仅在T
是WebFieldA
或其子类时才读取该属性。