javascript - route - set page title in angular 6




Verificação do tipo de interface com o Typescript (6)

Esta questão é o analogon direto para verificação de tipo de classe com TypeScript

Eu preciso descobrir em tempo de execução, se uma variável do tipo qualquer implementa uma interface. Aqui está meu código:

interface A{
    member:string;
}

var a:any={member:"foobar"};

if(a instanceof A) alert(a.member);

Se você inserir esse código no playground datilografado, a última linha será marcada como um erro, "O nome A não existe no escopo atual". Mas isso não é verdade, o nome existe no escopo atual. Eu posso até mudar a declaração da variável para var a:A={member:"foobar"}; sem reclamações do editor. Depois de navegar na web e encontrar a outra pergunta no SO, mudei a interface para uma classe, mas não posso usar literais de objeto para criar instâncias.

Eu me perguntava como o tipo A poderia desaparecer assim, mas uma olhada no javascript gerado explica o problema:

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

Não há representação de A como uma interface, portanto, nenhuma verificação de tipo de tempo de execução é possível.

Eu entendo que o javascript como uma linguagem dinâmica não tem conceito de interfaces. Existe alguma maneira de digitar a verificação de interfaces?

O autocompletar do playground datilografado revela que o typescript oferece até mesmo um método implements . Como posso usá-lo?


Agora é possível, acabei de lançar uma versão aprimorada do compilador TypeScript que fornece recursos de reflexão completos. Você pode instanciar classes de seus objetos de metadados, recuperar metadados de construtores de classe e inspecionar interface / classes em tempo de execução. Você pode conferir here

Exemplo de uso:

Em um de seus arquivos datilografados, crie uma interface e uma classe que a implemente da seguinte maneira:

interface MyInterface {
    doSomething(what: string): number;
}

class MyClass implements MyInterface {
    counter = 0;

    doSomething(what: string): number {
        console.log('Doing ' + what);
        return this.counter++;
    }
}

Agora vamos imprimir a lista de interfaces implementadas.

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

compilar com reflec-ts e lançá-lo:

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

Veja reflection.d.ts para detalhes do tipo meta da Interface .

ATUALIZAÇÃO: Você pode encontrar um exemplo completo de trabalho here


Aqui está outra opção: o módulo ts-interface-builder fornece uma ferramenta de tempo de construção que converte uma interface TypeScript em um descritor de tempo de execução, e ts-interface-checker pode verificar se um objeto satisfaz isto.

Para o exemplo do OP,

interface A {
  member: string;
}

Você executaria primeiro o ts-interface-builder que produz um novo arquivo conciso com um descritor, digamos, foo-ti.ts , que você pode usar assim:

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" 

Você pode criar uma função de proteção de tipo de uma linha:

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

Gostaria de salientar que o TypeScript não fornece um mecanismo direto para testar dinamicamente se um objeto implementa uma interface específica.

Em vez disso, o código TypeScript pode usar a técnica JavaScript de verificar se um conjunto apropriado de membros está presente no objeto. Por exemplo:

var obj : any = new Foo();

if (obj.someInterfaceMethod) {
    ...
}

No TypeScript 1.6, o protetor de tipo definido pelo usuário fará o trabalho.

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;
}

E, como Joe Yang mencionou: desde o TypeScript 2.0, você pode até aproveitar as vantagens do tipo de união marcado.

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;
}

E funciona também com o switch .


Você pode conseguir o que deseja sem a palavra-chave instanceof já que pode escrever proteções de tipos personalizados agora:

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);
}

Muitos membros

Se você precisar verificar muitos membros para determinar se um objeto corresponde ao seu tipo, você poderia adicionar um discriminador. O exemplo abaixo é o mais básico, e requer que você gerencie seus próprios discriminadores ... você precisaria se aprofundar nos padrões para garantir que você evite os discriminadores duplicados.

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);
}

mesmo que acima, onde as proteções definidas pelo usuário foram usadas, mas desta vez com um predicado de função de seta

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);






typescript