Typescript - interface extending another interface with nested properties

后端 未结 1 1201
太阳男子
太阳男子 2020-12-16 11:17

I have an interface like:

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

相关标签:
1条回答
  • 2020-12-16 11:50

    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: ''
        }
    }
    

    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;
        }
    }
    

    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: ''
        }
    }
    

    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: ''
        }
    }
    
    0 讨论(0)
提交回复
热议问题