¿Cómo puedo crear un objeto basado en una definición de archivo de interfaz en TypeScript?


313

He definido una interfaz como esta:

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

Defino una variable como esta:

var modal: IModal;

Sin embargo, cuando intento establecer la propiedad de modal, me da un mensaje que dice que

"cannot set property content of undefined"

¿Está bien usar una interfaz para describir mi objeto modal? De ser así, ¿cómo debo crearlo?

Respuestas:


426

Si está creando la variable "modal" en otro lugar, y quiere decirle a TypeScript que todo estará listo, usaría:

declare const modal: IModal;

Si desea crear una variable que realmente será una instancia de IModal en TypeScript, deberá definirla completamente.

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

O mienta, con una aserción de tipo, pero perderá la seguridad de tipo, ya que ahora quedará indefinido en lugares inesperados y posiblemente errores de tiempo de ejecución, al acceder, modal.contentetc. (propiedades que el contrato dice que estarán allí).

const modal = {} as IModal;

Clase de ejemplo

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

const modal = new Modal();

Puede pensar "oye, eso es realmente una duplicación de la interfaz", y está en lo correcto. Si la clase Modal es la única implementación de la interfaz IModal, es posible que desee eliminar la interfaz por completo y usar ...

const modal: Modal = new Modal();

Más bien que

const modal: IModal = new Modal();

2
Gracias. Tenía la esperanza de evitar tener que definir todos los contenidos modales inicialmente. ¿Sería más fácil si en lugar de una interfaz definiera Modal como una clase con propiedades y luego usara new y un constructor para configurar todos los valores iniciales?

1
Sí, podría definir una clase y luego solo tendría que crear nuevas instancias cuando las necesitara. ¿Necesitas un ejemplo?
Fenton

2
He agregado un ejemplo y una nota sobre la interfaz.
Fenton

21
var modal = <IModal>{};esto es lo que estaba buscando ;-) gracias!
Legends

55
Para su información, es mejor usar en {} as IModallugar de <IModal>{}. Elimina una ambigüedad en la gramática del lenguaje cuando se utilizan <foo>afirmaciones de estilo en JSX. Leer más . Y, por supuesto, usar leto en constlugar de var.
Alex Klaus

191

Si desea un objeto vacío de una interfaz, puede hacer simplemente:

var modal = <IModal>{};

La ventaja de usar interfaces en lugar de clases para estructurar datos es que si no tiene ningún método en la clase, se mostrará en JS compilado como un método vacío. Ejemplo:

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

compila en

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

que no tiene valor Las interfaces, por otro lado, no aparecen en JS mientras brindan los beneficios de la estructuración de datos y la verificación de tipos.


1
`Para agregar al comentario anterior. Para llamar a una función "updateModal (IModal modalInstance) {}", puede crear una instancia en línea de la interfaz 'IModal', como esta: // algún código aquí, donde la función updateModal y IModal son accesibles: updateModal (<IModal> {// esta línea crea un contenido de instancia: '', form: '', href: '', $ form: null, $ message: null, $ modal: null, $ submits: null}); // completa tu código '
Sunny

mediante el uso var modal= <abc>{}que acabamos de asignar modal de tipo abc de objeto vacío, pero ¿dónde hemos declarado el tipo de modal? Estoy usando typecript6.
Pardeep Jain

Esto no funcionó para mí, tuve que inicializar todo el objeto como se indica en la respuesta aceptada.
Rahul Sonwanshi


22

Creo que tienes básicamente cinco opciones diferentes para hacerlo. Elegir entre ellos podría ser fácil dependiendo de la meta que le gustaría alcanzar.

La mejor manera en la mayoría de los casos es usar una clase e instanciarla , porque está usando TypeScript para aplicar la verificación de tipos.

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

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

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

    foo(param: string): void {
    }
}

Incluso si otros métodos ofrecen formas más fáciles de crear un objeto desde una interfaz, debería considerar dividir su interfaz , si está usando su objeto para diferentes asuntos, y no causa una segregación excesiva de la interfaz:

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

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

Por otro lado, por ejemplo, durante la prueba de la unidad de su código (si no aplica la separación de preocupaciones con frecuencia), puede aceptar los inconvenientes en aras de la productividad. Puede aplicar otros métodos para crear simulacros principalmente para grandes interfaces de terceros * .d.ts. Y podría ser una molestia implementar siempre objetos anónimos completos para cada interfaz enorme.

En esta ruta, su primera opción es crear un objeto vacío :

 var modal = <IModal>{};

En segundo lugar, para realizar completamente la parte obligatoria de su interfaz . Puede ser útil si está llamando a bibliotecas JavaScript de terceros, pero creo que debería crear una clase, como antes:

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

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

En tercer lugar, puede crear solo una parte de su interfaz y crear un objeto anónimo , pero de esta manera usted es responsable de cumplir el contrato

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

    }
};

Resumiendo mi respuesta, incluso si las interfaces son opcionales, ya que no están transpuestas en código JavaScript, TypeScript está allí para proporcionar un nuevo nivel de abstracción, si se usa de manera inteligente y coherente. Creo que, solo porque puedes descartarlos en la mayoría de los casos de tu propio código, no deberías.



12

Como no he encontrado una respuesta igual en la parte superior y mi respuesta es diferente. Hago:

modal: IModal = <IModal>{}

2

Usando tu interfaz puedes hacer

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

Aquí hay otro enfoque:

Simplemente puede crear un objeto compatible con ESLint como este

const modal: IModal = {} as IModal;

O una instancia predeterminada basada en la interfaz y con valores predeterminados sensibles, si los hay

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

Luego, las variaciones de la instancia predeterminada simplemente anulando algunas propiedades

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

1

Muchas de las soluciones hasta ahora publicadas utilizan aserciones de tipo y, por lo tanto , no arrojan errores de compilación si se omiten las propiedades de interfaz requeridas en la implementación.

Para aquellos interesados ​​en otras soluciones robustas y compactas :

Opción 1: crear una instancia de una clase anónima que implemente la interfaz:

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

Opción 2: crear una función de utilidad:

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

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

0

Puede establecer valores predeterminados usando Class.

Sin constructor de clase:

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}

Con constructor de clase

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}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.