我正在尝试创建一个名为Actions的接口,该接口包含一个名为Options的属性,对于不同的操作,该属性会有所不同。
在类型定义中:
export interface Action{
id?: string;
type: string;
options: DrilldownOptions | SidepanelOptions;
}
export interface ActionOptions {
name: string;
icon?: any;
source?: string;
}
export interface DrilldownOptions extends ActionOptions{
page: string;
}
export interface SidepanelOptions extends ActionOptions{
widget: any
}
现在,我正尝试在我的执行方法中为每个操作访问这些内容。
因此执行向下钻取动作的执行者将使用
execute(action){
const page = action.options.page
}
这将导致错误。
SidepanelOptions上不存在属性页
是否有更好的方法来实现这种通用类型?
答案 0 :(得分:0)
如果您有类型为action
的变量Action
,那么您已经发现,直接访问action.options.page
是不安全的:
action.options.page; // error! Property 'page' does not exist on type 'SidepanelOptions'.
这是因为action.options
是联合体类型,并且未知至少在该联合体的一个成员上存在page
属性。要安全地访问page
,必须使用某种type guard将action.options
的类型从DrilldownOptions | SidepanelOptions
缩小到DrilldownOptions
。
例如,从TypeScript 2.7开始,您可以use the in
operator as a type guard:
if ("page" in action.options) {
action.options.page.charAt(0); // okay
} else {
action.options.widget; // okay
}
在“ then”子句中,action.options
缩小为DrillDownOptions
,在else
子句中,action.options
缩小为SidepanelOptions
。
如果要将变量page
设置为action.options.page
(如果存在),而将变量undefined
设置为in
,则可以使用const page = "page" in action.options ? action.options.page : undefined;
// const page: string | undefined
类型保护符和三元运算符,如下所示:
interface SomeOptions extends ActionOptions {
page?: string;
widget?: any;
}
另一种可行的方法是定义一个更广泛的选项类型,如下所示:
DrilldownOptions
SidepanelOptions
和SomeOptions
都可分配给Action
,反之亦然。然后,您可以拥有一个更广阔的interface ActionWider {
id?: string;
type: string;
options: SomeOptions;
}
界面:
Action
因此,ActionWider
可分配给ActionWider
。如果满足您的需求,则可以使用Action
代替action
。如果没有,您可以像这样安全地加宽const widerAction: ActionWider = action; // okay
:
const page2 = widerAction.options.page;
// const page2: string | undefined
然后在没有警告的情况下将其编入索引:
page2
请注意,string | undefined
的类型为action.options.page
,因为undefined
可能为page
。这与上面的template<enum Foo T = Bar> class Clazz {
分配具有相同的最终结果,而类型保护的争用较少。
好的,希望其中之一能有所帮助。祝你好运!