Como criar um objeto com base em uma definição de arquivo de interface no TypeScript?


313

Eu defini uma interface como esta:

interface IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
 }

Eu defino uma variável como esta:

var modal: IModal;

No entanto, quando tento definir a propriedade modal, isso me dá uma mensagem dizendo que

"cannot set property content of undefined"

Posso usar uma interface para descrever meu objeto modal e, em caso afirmativo, como devo criá-lo?

Respostas:


426

Se você estiver criando a variável "modal" em outro lugar e quiser informar ao TypeScript que tudo será feito, você deverá usar:

declare const modal: IModal;

Se você deseja criar uma variável que será realmente uma instância do IModal no TypeScript, será necessário defini-la completamente.

const modal: IModal = {
    content: '',
    form: '',
    href: '',
    $form: null,
    $message: null,
    $modal: null,
    $submits: null
};

Ou então, com uma declaração de tipo, mas você perderá a segurança de tipo, pois agora ficará indefinido em locais inesperados e possivelmente erros de tempo de execução ao acessar modal.contente assim por diante (propriedades que o contrato diz que estarão lá).

const modal = {} as IModal;

Classe de exemplo

class Modal implements IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
}

const modal = new Modal();

Você pode pensar "ei, isso é realmente uma duplicação da interface" - e você está correto. Se a classe Modal for a única implementação da interface IModal, você poderá excluir a interface completamente e usar ...

const modal: Modal = new Modal();

Ao invés de

const modal: IModal = new Modal();

2
Obrigado. Eu esperava deixar de ter que definir todo o conteúdo modal inicialmente. Seria mais fácil se, em vez de uma interface, eu definisse Modal como uma classe com propriedades e usasse new e um construtor para configurar todos os valores iniciais?

1
Sim - você pode definir uma classe e só precisará criar novas instâncias quando precisar delas. Você precisa de um exemplo?
Fenton

2
Eu adicionei um exemplo e uma observação sobre a interface.
Fenton

21
var modal = <IModal>{};era isso que eu estava procurando ;-) obrigado!
Legends

5
Para sua informação, é melhor usar {} as IModaldo que usar <IModal>{}. Remove uma ambiguidade na gramática do idioma ao usar <foo>asserções de estilo em JSX. Leia mais . E, claro, use letou em constvez de var.
Alex Klaus

191

Se você deseja um objeto vazio de uma interface, pode fazer exatamente:

var modal = <IModal>{};

A vantagem de usar interfaces no lugar de classes para estruturar dados é que, se você não tiver nenhum método na classe, ele será exibido no JS compilado como um método vazio. Exemplo:

class TestClass {
    a: number;
    b: string;
    c: boolean;
}

compila em

var TestClass = (function () {
    function TestClass() {
    }
    return TestClass;
})();

que não carrega valor. As interfaces, por outro lado, não aparecem no JS, ao mesmo tempo em que fornecem os benefícios da estruturação de dados e da verificação de tipo.


1
`Para adicionar ao comentário acima. Para chamar uma função "updateModal (IModal modalInstance) {}", você pode criar uma instância embutida da interface 'IModal', assim: // algum código aqui, onde a função updateModal e IModal estão acessíveis: updateModal (<IModal> {// esta linha cria um conteúdo da instância: '', form: '', href: '', $ form: null, $ message: null, $ modal: null, $ submete: null}); // complete seu código `
Sunny

usando var modal= <abc>{}apenas atribuímos o modal do tipo abc do objeto vazio, mas onde declaramos o tipo de modal? Estou usando o typescript6.
Pardeep Jain

Isso não funcionou para mim. Eu tive que inicializar todo o objeto, conforme indicado na resposta aceita.
Rahul Sonwanshi 27/02


22

Eu acho que você tem basicamente cinco opções diferentes para fazer isso. Escolher entre eles pode ser fácil, dependendo do objetivo que você deseja alcançar.

A melhor maneira, na maioria dos casos, de usar uma classe e instancia-la , porque você está usando o TypeScript para aplicar a verificação de tipo.

interface IModal {
    content: string;
    form: string;
    //...

    //Extra
    foo: (bar: string): void;
}

class Modal implements IModal {
    content: string;
    form: string;

    foo(param: string): void {
    }
}

Mesmo que outros métodos ofereçam maneiras mais fáceis de criar um objeto a partir de uma interface, considere dividir sua interface , se você estiver usando seu objeto para assuntos diferentes e isso não causar excesso de segregação de interface:

interface IBehaviour {
    //Extra
    foo(param: string): void;
}

interface IModal extends IBehaviour{
    content: string;
    form: string;
    //...
}

Por outro lado, por exemplo, durante o teste unitário de seu código (se você não aplicar a separação de preocupações com frequência), poderá aceitar as desvantagens por uma questão de produtividade. Você pode aplicar outros métodos para criar simulações principalmente para grandes interfaces de terceiros * .d.ts. E pode ser difícil implementar sempre objetos anônimos completos para todas as interfaces enormes.

Nesse caminho, sua primeira opção é criar um objeto vazio :

 var modal = <IModal>{};

Em segundo lugar, para realizar plenamente a parte obrigatória da sua interface . Pode ser útil se você estiver chamando bibliotecas JavaScript de terceiros, mas acho que você deve criar uma classe, como antes:

var modal: IModal = {
    content: '',
    form: '',
    //...

    foo: (param: string): void => {
    }
};

Terceiro, você pode criar apenas uma parte da sua interface e criar um objeto anônimo , mas dessa forma você é responsável por cumprir o contrato

var modal: IModal = <any>{
    foo: (param: string): void => {

    }
};

Resumindo minha resposta, mesmo que as interfaces sejam opcionais, porque não são transpiladas para o código JavaScript, o TypeScript existe para fornecer um novo nível de abstração, se usado com sabedoria e consistência. Eu acho que só porque você pode descartá-los na maioria dos casos do seu próprio código, não deveria.



12

Como não encontrei uma resposta igual no topo e minha resposta é diferente. Eu faço:

modal: IModal = <IModal>{}

2

Usando sua interface, você pode fazer

class Modal() {
  constructor(public iModal: IModal) {
   //You now have access to all your interface variables using this.iModal object,
   //you don't need to define the properties at all, constructor does it for you.
  }
}

2

Aqui está outra abordagem:

Você pode simplesmente criar um objeto compatível com ESLint como este

const modal: IModal = {} as IModal;

Ou uma instância padrão baseada na interface e com padrões sensíveis, se houver

const defaultModal: IModal = {
    content: "",
    form: "",
    href: "",
    $form: {} as JQuery,
    $message: {} as JQuery,
    $modal: {} as JQuery,
    $submits: {} as JQuery
};

Em seguida, variações da instância padrão simplesmente substituindo algumas propriedades

const confirmationModal: IModal = {
    ...defaultModal,     // all properties/values from defaultModal
    form: "confirmForm"  // override form only
}

1

Muitas das soluções postadas até agora usam asserções de tipo e, portanto , não geram erros de compilação se as propriedades de interface necessárias forem omitidas na implementação.

Para os interessados ​​em outras soluções robustas e compactas :

Opção 1: Instanciar uma classe anônima que implementa a interface:

new class implements MyInterface {
  nameFirst = 'John';
  nameFamily = 'Smith';
}();

Opção 2: Crie uma função de utilitário:

export function impl<I>(i: I) { return i; }

impl<MyInterface>({
  nameFirst: 'John';
  nameFamily: 'Smith';
})

0

Você pode definir valores padrão usando Class.

Sem construtor de classe:

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
};

class Modal implements IModal {
  content = "";
  form = "";
  href: string;  // will not be added to object
  isPopup = true;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}

Com construtor de classe

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
}

class Modal implements IModal {
  constructor() {
    this.content = "";
    this.form = "";
    this.isPopup = true;
  }

  content: string;

  form: string;

  href: string; // not part of constructor so will not be added to object

  isPopup: boolean;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.