Pesquisa de site

sintaxe - Typescript - interface estendendo outra interface com propriedades aninhadas


Eu tenho uma interface assim:

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

Como posso estender isso, de forma que eu adicione algumas novas propriedades à estrutura, sem me repetir? Eu preciso criar uma nova interface para a estrutura e estender isso e criar um novo Módulo com a nova interface da estrutura ou existe alguma outra sintaxe para conseguir isso?

Idealmente, eu apenas escreveria algo como:

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

export interface UrlModule extends Module {
  structure: {
    url: string;
  }
}

Obrigado!

Resposta #1

Interfaces não podem adicionar aos tipos de membros na interface base (pelo menos não diretamente). Você pode usar um tipo de interseção em vez disso:

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

Eles devem se comportar de maneira semelhante às interfaces, podem ser implementados por classes e serão verificados quando você atribuir literais de objeto a eles.

Você também pode fazer isso com interfaces, mas é um pouco mais verboso, e implica usar uma consulta de tipo para obter o tipo original do campo, e novamente uma interseção:

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

export interface UrlModule extends Module {
    structure: Module['structure'] & {
        url: string;
    }
}

A opção realmente verbosa (embora, de certa forma, mais fácil de entender) é, é claro, simplesmente definir uma interface separada para a estrutura:

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

Editar

Como sugestão do @jcalz, também poderíamos tornar a interface do módulo genérica e passar a interface de estrutura apropriada:

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

Artigos relacionados