Typescript-接口扩展带有嵌套属性的另一个接口

Kal*_*rov 7 syntax typescript

我有一个类似的界面:

export interface Module {
  name: string;
  data: any;
  structure: {
    icon: string;
    label: string;
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

如何扩展它,以便向结构添加一些新属性,而无需重复我自己?我是否必须为结构创建一个新的接口并对其进行扩展,并使用新的结构接口创建一个新的Module,还是有其他语法可以实现此目的?

理想情况下,我将只写以下内容:

export interface DataModule extends Module {
  structure: {
    visible: boolean;
  }
}

export interface UrlModule extends Module {
  structure: {
    url: string;
  }
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Tit*_*mir 5

Interfaces can't add to the types of members in the base interface (at least not directly). You can use an intersection type instead:

export interface Module {
name: string;
data: any;
    structure: {
        icon: string;
        label: string;
    }
}

export type DataModule = Module & {
    structure: {
        visible: boolean;
    }
}

export type UrlModule = Module & {
    structure: {
        url: string;
    }
}

let urlModule: UrlModule = {
    name: "",
    data: {},
    structure: {
        icon: '',
        label: '',
        url: ''
    }
}
Run Code Online (Sandbox Code Playgroud)

They should behave similarly to interfaces, they can be implemented by classes and they will get checked when you assign object literals to them.

You can also do it with interfaces but it's a bit more verbose, and implies using a type query to get the original type of the field, and again an intersection:

export interface DataModule extends Module {
    structure: Module['structure'] & {
        visible: boolean;
    }
}

export interface UrlModule extends Module {
    structure: Module['structure'] & {
        url: string;
    }
}
Run Code Online (Sandbox Code Playgroud)

The really verbose option (although in some ways simpler to understand) is of course to just define a separate interface for structure:

export interface IModuleStructure {        
    icon: string;
    label: string;
}
export interface Module {
    name: string;
    data: any;
    structure: IModuleStructure
}
export interface IDataModuleStructure extends IModuleStructure{
    visible: boolean;
}
export interface DataModule extends Module {
    structure: IDataModuleStructure 
}
export interface IUrlModuleStructure extends IModuleStructure {
    url: string;
}
export interface UrlModule extends Module {
    structure: IUrlModuleStructure
}
let urlModule: UrlModule = {
    name: "",
    data: {},
    structure: {
        icon: '',
        label: '',
        url: ''
    }
}
Run Code Online (Sandbox Code Playgroud)

Edit

As pe @jcalz suggestion, we could also make the module interface generic, and pass in the apropriate structure interface:

export interface IModuleStructure {        
    icon: string;
    label: string;
}
export interface Module<T extends IModuleStructure = IModuleStructure> {
    name: string;
    data: any;
    structure: T
}
export interface IDataModuleStructure extends IModuleStructure{
    visible: boolean;
}
export interface DataModule extends Module<IDataModuleStructure> {
}
export interface IUrlModuleStructure extends IModuleStructure {
    url: string;
}
export interface UrlModule extends Module<IUrlModuleStructure> {
}
let urlModule: UrlModule = { // We could also just use Module<IUrlModuleStructure>
    name: "",
    data: {},
    structure: {
        icon: '',
        label: '',
        url: ''
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 对“模块”使用泛型怎么样?或者这个建议太复杂了? (2认同)