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