traductor online official namespace first convertir codigo app javascript compiler-construction interface web typescript

javascript - online - typescript object



Verificación del tipo de interfaz con Typescript (9)

Esta pregunta es el análogo directo a la verificación del tipo de clase con TypeScript

Necesito averiguar en tiempo de ejecución si una variable de tipo cualquiera implementa una interfaz. Aquí está mi código:

interface A{ member:string; } var a:any={member:"foobar"}; if(a instanceof A) alert(a.member);

Si ingresa este código en el área de juegos de mecanografía, la última línea se marcará como un error, "El nombre A no existe en el alcance actual". Pero eso no es cierto, el nombre existe en el alcance actual. Incluso puedo cambiar la declaración de variable a var a:A={member:"foobar"}; sin quejas del editor. Después de navegar en la web y encontrar la otra pregunta en SO, cambié la interfaz a una clase, pero luego no puedo usar los literales de objetos para crear instancias.

Me pregunté cómo podría desaparecer el tipo A de esa manera, pero un vistazo al javascript generado explica el problema:

var a = { member: "foobar" }; if(a instanceof A) { alert(a.member); }

No hay representación de A como interfaz, por lo tanto, no es posible verificar el tipo de tiempo de ejecución.

Entiendo que javascript como un lenguaje dinámico no tiene ningún concepto de interfaces. ¿Hay alguna manera de escribir verificación para las interfaces?

El autocompletado del parque de juegos mecanografiado revela que el mecanografiado incluso ofrece un método implements . Como puedo usar lo ?


¿Qué hay de guardias de tipo definido por el usuario? https://www.typescriptlang.org/docs/handbook/advanced-types.html

interface Bird { fly(); layEggs(); } interface Fish { swim(); layEggs(); } function isFish(pet: Fish | Bird): pet is Fish { //magic happens here return (<Fish>pet).swim !== undefined; } // Both calls to ''swim'' and ''fly'' are now okay. if (isFish(pet)) { pet.swim(); } else { pet.fly(); }


Ahora es posible, acabo de lanzar una versión mejorada del compilador de TypeScript que proporciona capacidades de reflexión completa. Puede instanciar clases desde sus objetos de metadatos, recuperar metadatos de constructores de clases e inspeccionar interfaces / clases en tiempo de ejecución. Puedes verlo here

Ejemplo de uso:

En uno de sus archivos de texto mecanografiado, cree una interfaz y una clase que lo implemente de la siguiente manera:

interface MyInterface { doSomething(what: string): number; } class MyClass implements MyInterface { counter = 0; doSomething(what: string): number { console.log(''Doing '' + what); return this.counter++; } }

ahora imprimamos la lista de interfaces implementadas.

for (let classInterface of MyClass.getClass().implements) { console.log(''Implemented interface: '' + classInterface.name) }

compilar con Reflec-ts y ejecutarlo:

$ node main.js Implemented interface: MyInterface Member name: counter - member kind: number Member name: doSomething - member kind: function

Consulte reflection.d.ts para ver los detalles del meta-tipo de Interface .

ACTUALIZACIÓN: puede encontrar un ejemplo completo de trabajo here


Aquí hay otra opción: el módulo ts-interface-builder proporciona una herramienta de tiempo de compilación que convierte una interfaz de TypeScript en un descriptor de tiempo de ejecución, y ts-interface-checker puede verificar si un objeto lo satisface.

Para el ejemplo de OP,

interface A { member: string; }

Primero ejecutaría ts-interface-builder que produce un nuevo archivo conciso con un descriptor, por ejemplo, foo-ti.ts , que puede usar así:

import fooDesc from ''./foo-ti.ts''; import {createCheckers} from "ts-interface-checker"; const {A} = createCheckers(fooDesc); A.check({member: "hello"}); // OK A.check({member: 17}); // Fails with ".member is not a string"

Puede crear una función type-liner type-guard:

function isA(value: any): value is A { return A.test(value); }


En TypeScript 1.6, guardián de tipo definido por el usuario hará el trabajo.

interface Foo { fooProperty: string; } interface Bar { barProperty: string; } function isFoo(object: any): object is Foo { return ''fooProperty'' in object; } let object: Foo | Bar; if (isFoo(object)) { // `object` has type `Foo`. object.fooProperty; } else { // `object` has type `Bar`. object.barProperty; }

Y tal como mencionó Joe Yang: desde TypeScript 2.0, incluso puede aprovechar la ventaja del tipo de unión etiquetada.

interface Foo { type: ''foo''; fooProperty: string; } interface Bar { type: ''bar''; barProperty: number; } let object: Foo | Bar; // You will see errors if `strictNullChecks` is enabled. if (object.type === ''foo'') { // object has type `Foo`. object.fooProperty; } else { // object has type `Bar`. object.barProperty; }

Y funciona con el switch también.


Me gustaría señalar que TypeScript no proporciona un mecanismo directo para probar dinámicamente si un objeto implementa una interfaz particular.

En cambio, el código TypeScript puede usar la técnica de JavaScript para verificar si hay un conjunto apropiado de miembros en el objeto. Por ejemplo:

var obj : any = new Foo(); if (obj.someInterfaceMethod) { ... }


Puede lograr lo que quiere sin la palabra clave instanceof ya que puede escribir guardias de tipo personalizado ahora:

interface A{ member:string; } function instanceOfA(object: any): object is A { return ''member'' in object; } var a:any={member:"foobar"}; if (instanceOfA(a)) { alert(a.member); }

Muchos miembros

Si necesita verificar un montón de miembros para determinar si un objeto coincide con su tipo, en su lugar podría agregar un discriminador. El siguiente es el ejemplo más básico y requiere que administres tus propios discriminadores ... necesitarás profundizar en los patrones para asegurarte de evitar duplicadores discriminadores.

interface A{ discriminator: ''I-AM-A''; member:string; } function instanceOfA(object: any): object is A { return object.discriminator === ''I-AM-A''; } var a:any = {discriminator: ''I-AM-A'', member:"foobar"}; if (instanceOfA(a)) { alert(a.member); }


TypeGuards

interface MyInterfaced { x: number } function isMyInterfaced(arg: any): arg is MyInterfaced { return arg.x !== undefined; } if (isMyInterfaced(obj)) { (obj as MyInterfaced ).x; }


igual que en el caso anterior donde se usaron protecciones definidas por el usuario, pero esta vez con un predicado de función de flecha

interface A { member:string; } const check = (p: any): p is A => p.hasOwnProperty(''member''); var foo: any = { member: "foobar" }; if (check(foo)) alert(foo.member);


mecanografiado 2.0 introduce la unión etiquetada

Funciones de Typescript 2.0

interface Square { kind: "square"; size: number; } interface Rectangle { kind: "rectangle"; width: number; height: number; } interface Circle { kind: "circle"; radius: number; } type Shape = Square | Rectangle | Circle; function area(s: Shape) { // In the following switch statement, the type of s is narrowed in each case clause // according to the value of the discriminant property, thus allowing the other properties // of that variant to be accessed without a type assertion. switch (s.kind) { case "square": return s.size * s.size; case "rectangle": return s.width * s.height; case "circle": return Math.PI * s.radius * s.radius; } }