• Nenhum resultado encontrado

Outros tipo

No documento Introdução ao Typescript (páginas 66-90)

Unions

1) Usamos o conceito de união para definir que o parâmetro poderá ser do

tipo string ou number.

2) Usamos a função com os

dois tipos de parâmetros.

3) O tipo “any” poderia ter sido usado, contudo, o usuário tem a possibilidade

de usar um tipo boolean, o que não é o desejado.

interface Bird { raca: string; fly(); layEggs(); } interface Fish { raca: string; swim(); layEggs(); }

function getSmallPet(): Fish | Bird {

let f: Fish;

return f; }

let pet = getSmallPet();

pet.layEggs(); // Correto

pet.swim(); // Erro

class Cliente {

endereco: string;

constructor(public nome: string){} }

class Fornecedor {

telefone: string;

constructor(public nome: string){} }

let x1: Cliente|Fornecedor;

x1 = new Cliente('Jorge');

x1.endereco = 'Rua do centro';

console.log(x1.endereco);

x1 = new Fornecedor('Farmácia');

x1.telefone = '2222-2222';

console.log(x1.telefone);

Outros tipo

Unions

1) Quando recorremos a uma união para definir o tipo de um objeto, o compilador só permite o uso de membros comum

ao tipo instanciado.

2) Quando recorremos a valores que tem o tipo união, somente os

membros em comum dos tipos podem ser

let aa: number = 9;

console.log(typeof aa); // "mumber"

console.log(typeof {}); // "object"

console.log(typeof []); // "object"

console.log(typeof new Date()); // "object"

console.log(typeof new RegExp('')); // "object"

console.log(typeof null); // "object"

Outros tipo

Guardas

1) Não descobrimos qual a classe do objeto, somos informados apenas que é

um objeto.

• Em Javascript é normal verificar se a variável é de um determinado tipo. Isso é necessário, pois as variáveis podem ser uniões de tipo. Para isso temos as palavras reservadas typeof, instanceof e in.

• O operador typeof trabalha em um variável e retorna uma string, indicando o tipo do valor.

• O operador typeof é excelente para reconhecimento de valores primitivos, como os acima citados. Para detecção de valores de referência, entretanto, eles não possuem serventia:

•Para strings, typeof retorna“string.” •Para numbers, typeof retorna“number.” •Para booleans, typeof retorna“boolean.” •Para undefined, typeof retorna“undefined.”

Outros tipo

Guardas

• O operador instanceof distingue instâncias de classes diferentes.

• Ainda temos o operador in para verificar se existe algum determinado membro em um objeto:

console.log({} instanceof Object); // "object"

console.log([] instanceof Array); // "object"

console.log( new Date() instanceof Date); // "object"

console.log(new RegExp('') instanceof RegExp); // "object"

interface Point {

x: number;

y: number;}

interface Point3d extends Point {

z: number;}

function plot(point: Point) {

if ('z' in point) { // point é um `Point3D` } else { // point é um `Point` } }

interface Square { kind: "square"; size: number; } interface Rectangle { kind: "rectangle"; width: number; height: number; } interface Circle { kind: "circle"; radius: number; }

function area(s: Square | Rectangle | Circle) {

switch (s.kind) {

case "square": return s.size * s.size;

case "rectangle": return s.height * s.width;

case "circle": return Math.PI * s.radius ** 2; }

}

let forma: Circle = {kind: "circle", radius: 3.15};

console.log( area(forma) );

Outros tipo

Discriminated unions ou tagged Unions

• Existe um outro recurso de guarda, o qual consiste em criar um campo em comum entre os tipos, assim o compilador é capaz de inferir o tipo de acordo com esse campo em uma condição if ou switch.

interface IPessoa{ nome: string; } interface IAluno{ escola: string; }

function imprimeInfo( estudante : IPessoa & IAluno){

console.log( `${estudante.nome} matriculado na escola

${estudante.escola}` ); }

let jorge = {nome: 'Jorge Silva', escola: 'Militar'};

imprimeInfo(jorge);

Outros tipo

Interseções de tipos

• As interseções (&) são tipos personalizados criados a partir da combinação de vários tipos. Assim, o objeto assume simultaneamente a identidade de todos os tipos e será

Outros tipo

Aliases

• Aliases permite criar nomes alternativos para tipos existentes. Não se trata de um novo tipo, mas são uteis para a redução de código e para melhorar a abstração dos problemas. Pode-se renomear tipos primitivos, uniões, tuplas, entre outros tipos criados pelo usuário.

type Nome = string;

type NomeCorreto = () => string;

type NomeOrNomeCorreto = Nome | NomeCorreto;

function getName(n: NomeOrNomeCorreto): Nome {

if (typeof n === "string") { return n; } else return n(); } type Tree = { value: number; left: Tree; right: Tree; }

type Matriculado = IPessoa & IAluno;

function imprimeNovo( estudante : Matriculado){

console.log( `${estudante.nome} matriculado na escola ${estudante.escola}` ); }

1) Usamos a palavra reservada typepara criar os apelidos. Podemos criar

apelidos utilizando outros apelidos e dar apelidos

Outros tipo

String literal Types

• String literal types permitem criar um novo tipo de dados em que o tipo string recebe exatamente os valores que foram especificados na definição.

let resposta: "Sim" | "Não";

resposta = "Sim";

//resposta = "talvez"; <===Erro

type Easing = "ease-in" | "ease-out" | "ease-in-out";

class UIElement {

animate(dx: number, dy: number, easing: Easing) {

if (easing === "ease-in") {

// ...

}

else if (easing === "ease-out") { }

else if (easing === "ease-in-out") { }

else {

// error! should not pass null or undefined.

} } }

let button = new UIElement();

button.animate(0, 0, "ease-in");

Outros tipo

Iteradores

• Typescript implementou os conceitos de iterable e iterator. Se o objeto devolver um iterator a partir de uma propriedade que referencia uma função acessada pelo símbolo Symbol.iterator, ele passa a ser um iterable.

• Vários dos tipos introduzidos pela linguagem (ex.: Array, Map, Set, String) são iterables. • A forma mais fácil de iterar sobre essas coleções é através das instruções for..of e for..in

let list = [4, 5, 6];

for (let i in list) {

console.log(i); // "0", "1", "2",

}

for (let i of list) {

console.log(i); // "4", "5", "6"

}

let iterar = {nome: 'Bruno’,

sobrenome: 'Ferreira'};

for (let i in iterar) {

console.log(i); }

for (let i of iterar) {

console.log(i); }

for..of for..in

Acessa o valor Acessa a chave que retorna o valor Aplicado somente a objetos iterables Pode ser aplicado a qualquer objeto Percorre o objeto sem conhecer a forma Percorre o objeto sem conhecer a forma

1) O primeiro laço retorna os índices, o

segundo os valores desses índices.

2) O primeiro laço retorna o nome das

propriedades, o segundo mostra um erro de compilação, pois o objeto não é

class Flies {

fly() {

console.log('voando...'); }

}

class Climbs {

climb() {

console.log(‘subindo na parede'); }

}

Outros tipo

Mixim ou herança múltiplas

• Typescript permite a criação de classes a partir da combinação de outras. Fornecendo assim herança múltipla. Tem-se que seguir três passos para obter o resultado esperado:

1. Utilizar a palavra implements ao invés de extends durante a composição da nova classe;

2. Redeclarar as propriedades e os métodos como propriedades na nova classe.

3. Criar um método chamada applyMixins com os argumentos corretos.

1) Começamos com duas classes simples que representam superpoderes de

class BeetleGuy implements Climbs, Flies { climb: () => void; fly: () => void; sting(){ this.fly(); this.climb();

console.log('ferroa!!'); }

}

function applyMixins(derivedCtor: any, baseCtors: any[]) {

baseCtors.forEach(baseCtor => {

Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {

if (name !== 'constructor') {

derivedCtor.prototype[name] = baseCtor.prototype[name]; }

}); });

}

applyMixins (BeetleGuy, [Climbs, Flies]);

let superBesouro = new BeetleGuy();

superBesouro.sting();

Outros tipo

Mixim ou herança múltiplas

2) Criamos uma terceira classe que herda os poderes das duas primeiras classes (herança múltipla), para qual usamos a

palavra chave implements.

3) Redeclaramos todos os métodos como propriedades,

nesse caso, não existiam

propriedades a serem herdadas. 4) Criamos o seguinte método

para que o compilador consiga fazer a transcrição da herança múltipla para o Javascript. Esse método pode ser criado e inserido

em um módulo para ser aplicado quando necessário.

5) Registramos a classe com herança múltipla utilizando o

método criado e, por fim, utilizamos a nova classe instanciando um objeto.

function compara<T>(parametro1: T, parametro2: T): boolean{

return parametro1 == parametro2; }

console.log(compara<number>(10,20));

console.log(compara<string>('bh','sp’));

console.log(compara(true,true));

Outros tipo

Generics

• Typescript, como outras linguagens oferece o recurso de generics, o qual visa aumentar a

reusabilidade de código tornando os tipos de dados genéricos, isso sem perder a verificação de tipos.

• Um exemplo clássico é o uso de coleções que são capazes de se adaptarem a diferentes tipos de objetos ou tipos primitivos.

• Veja um exemplo abaixo, aonde não queremos usar o tipo any, para dar mais segurança referente os tipos de dados a uma função que compara se os valores são iguais:

1) Introduzimos um ou mais parâmetro de tipos, de qualquer nome (padrão T) que serve

como um placeholder para tipos concretos.

2) Definimos o tipo da função quando ela é invocada. 3) Se omitirmos o placeholder, o compilador tentará inferir o tipo.

interface Molde { <T>(arg: T): T; }

function identidade<T>(arg: T): T {

return arg; }

let myIdentity: Molde = identidade;

console.log(myIdentity<number>(1000));

function identity<T>(arg: T): T {

return arg; }

let myIdentity: <U>(arg: U) => U = identity;

console.log(myIdentity(3000));

Outros tipo

Generics

• Pode-se usar diferentes nomes para os parâmetros de tipos genéricos:

• Pode-se utilizar generics em funções de uma interface, isso pode ser feito de duas formas: 1) Usamos o nome “T” para a definição da função e o nome “Q” para a definição de um tipo que irá receber a função, o qual mantém

a mesma assinatura da função identity.

2) Declaramos o tipo genérico na função da interface. 3) Se omitirmos o placeholder, o compilador tentará inferir o tipo. interface Molde<T> { (arg: T): T; }

function identidade<T>(arg: T): T {

return arg; }

let myIdentity: Molde<number> = identidade;

console.log(myIdentity(1000));

2) Declaramos o tipo genérico na definição da

class Generica<U>{

constructor(public t: U){} }

let g = new Generica<boolean>(true);

console.log(g.t);

class AdicionaGenerico<T> {

valorInicial: T;

add: (x: T, y: T) => T; }

let myGenericNumber = new AdicionaGenerico<number>();

myGenericNumber.valorInicial = 0;

myGenericNumber.add = function(x, y) { return x + y; };

console.log(myGenericNumber.add(100,400));

let stringNumeric = new AdicionaGenerico<string>();

stringNumeric.valorInicial = " ";

stringNumeric.add = function(x, y) { return x + y; };

console.log(stringNumeric.add(stringNumeric.valorInicial, "test"));

• Pode-se utilizar generics em classes, isso pode ser feito da seguinte forma:

• Outro exemplo:

Outros tipo

Generics 1) Classe com o tipo genérico definido na declaração da classe. 2) Instanciamos dois objetos com

tipos diferentes.

3) Propriedade definida com

generics no construtor

• O compilador Typescript, em muitas das vezes, não consegue prever se um parâmetro do tipo genérico tem uma determinada propriedade ou método. Veja o exemplo abaixo:

• Contudo, temos que garantir que o tipo passada terá esse método ou propriedade e isso é feito criando uma interface (contrato) em conjunto com a palavra reservada extends durante a

declaração do tipo genérico:

function registrar<T>(arg: T): T {

console.log(arg.length);

return arg; }

Outros tipo

Generics Constraints

1) Essa linha apresenta um erro, o compilador não reconhece o método lenght

interface Comprimento {

length: number; }

function registrar<T extends Comprimento>(arg: T): T {

console.log(arg.length);

return arg; }

• Outro exemplo:

• Podemos aprofundar nos exemplos criando restrições entre os parâmetros de tipo genéricos:

function getProperty<T, K extends keyof T>(obj: T, key: K) {

return obj[key]; }

let xs = { a: 1, b: 2, c: 3, d: 4 };

let retorno = getProperty(xs, 'a'); // okay

console.log(retorno);

//retorno = getProperty(xs, 'm'); //Erro: não existe a chave 'm' //console.log(retorno);

Outros tipo

Generics Constraints

2) O tipo k têm os mesmos membros que o elemento T.

interface PropriedadeNome{

nome:string; }

class PessoaFisica{

constructor(public nome: string){} }

class PessoaJuridica{

constructor(public nome: string){} }

function envia<Y extends PropriedadeNome>(obj:Y){

console.log('get:http:\\\\localhost\\8080\\'+obj.nome); }

envia({nome: 'matriz'});

1) O tipo Y tem a propriedade nome.

• Promise é um tipo de dado que tenta solucionar problemas relacionados com tarefas assíncronas em cadeia.

• Esse tipo de dado é responsável por notificar acerca da sua conclusão. Sua especificação é direta

• Promises aceitam uma função por parâmetro. Esta função será executada recebendo duas novas funções em seus argumentos – uma para resolver a promise, outra para rejeitá-la. Caso um erro aconteça dentro de uma promise, ela também será rejeitada.

• Uma promise possui dois métodos principais:

then: Executado quando a promise é resolvida; catch: Executado em caso de rejeição (ou throw).

Outros tipo

Tipo Promises

let pr = new Promise ( (resolve, reject) => {

// resolva ou rejeite

• Exemplo 1:

• Tanto a função resolve quanto a reject podem ser executadas apenas uma vez dentro de uma promise.

• Já o método then pode ser usado várias vezes para a mesma promise.

Outros tipo

Tipo Promises

let pr = new Promise ( (resolve, reject) => {

resolve(10); });

pr.then(valor => console.log(value));

1) Nome padrão das funções para aceitar e

rejeitar a promessa.

2) Quando executarmos a promessa, ela dirá que o processamento foi resolvido e

o valor final é 10.

2) O método then é acionado com a promessa resolvida. A

variável “valor” recupera o retorno da promessa.

let pr2 = new Promise ( function (resolve, reject) {

resolve(100); });

pr2.then( (valor) => {console.log(valor); return 200;}) .then( (v) => console.log(v))

.catch( (err) => console.log('erro!'));

4) Caso o método reject tivesse sido acionado dentro da

promise, o catch seria executado.

function abrirArquivo() : Promise<String>{

return new Promise( (resolve,reject) => {

//abrindo o arquivo...

let correto = true;

if (correto)

resolve("Aberto..")

reject("erro ao abrir o arquivo.") });

}

function lerArquivo() : Promise<String>{

return new Promise( (resolve,reject) => {

//abrindo o arquivo...

let correto = false;

if (correto)

resolve("Lendo..")

reject("erro ao ler o arquivo.") });

}

function fecharArquivo() : Promise<String>{

return new Promise( (resolve,reject) => {

//abrindo o arquivo...

let correto = true;

if (correto)

resolve("Fechando..")

reject("erro ao fechar o arquivo.") });

}

abrirArquivo()

.then( () => lerArquivo()

.then( () => fecharArquivo()

.then( () => console.log('tudo certo!'))

.catch( (errFechar) => console.log(errFechar)) .catch( (errLer) => console.log(errLer) ) ) )

.catch( (errAbrrir) => console.log(errAbrrir));

• Exemplo 2:

Outros tipo

Tipo Promises 1) Geralmente usamos

Promise como retorno de funções.

2) Uma das grandes vantagens de Promise é que podemos encadear ações em ambientes

assíncronos. Contudo, simulamos uma ação de três passos que é o de abrir, ler e

• all: retorna uma promise pendente que será resolvida quando todas as promises passadas por parâmetro (array) forem resolvidas. Ela será rejeitada se qualquer uma das promises rejeitar. • race: retorna uma promise pendente, mas ela será resolvida assim que qualquer uma das

promises enviadas seja resolvida, se uma delas falhar antes de qualquer uma ser resolvida, então essa promise será rejeitada.

Outros tipo

• A modularização é um importante conceito para a organização do código fonte, melhorando a legibilidade e consequentemente a manutenção dos sistemas, a partir da ECMAScript 2015 o Typescript passou a dar suporte a esse conceito;

• O problema é que o conceito foi introduzido recentemente então a comunidade Javascript resolvia essa ausência propondo soluções diferentes, o que gerou diversos padrões (sintaxes) de criação de módulos, ex.:

• CommonsJS – implementação de módulos do NodeJS;

• AMD (Assynchronous Module Definition) – formato popular proposto por alguns fabricantes de browsers;

• UMD (Universal Module Definition) – formato que combina os dois primeiros e podem rodar no NodeJS e no

browser;

• System – formato que suporta vários formatos;

• ES2015 – formato propostos pelo ECMAScript 2015 e implementado pelo TypeScript.

Módulos

• Um módulo pode ser considerado como um arquivo que importa ou exporta código fonte; • Cada módulo tem seu próprio contexto, ou seja, seus elementos são visíveis somente dentro

dele, a menos que os exportemos, assim outros módulos podem acessar esses elementos;

• Um module loader é o responsável por carregar os módulos que um importador está

requisitando. O NodeJS (servidor) possui esse loader, mas os browseres (cliente) não, assim temos que usar bibliotecas externar para resolver esse problema. Exemplos:

Módulos

Introdução

Bibliotecas Formatos suportados

RequireJS AMD

• A exportação de um elemento por um módulo é feita através da palavra reservada export. • A importação de um elemento por um módulo é feita através da palavra reservada import.

Módulos

Sintaxe

import {Carro} from './modelo1';

let uno = new Carro('Uno Hatch', 25000.00);

console.log(`Carro: ${uno.tipo} custa: ${uno.valor}`);

export class Carro{

constructor (public tipo: string, public valor: number){} }

module1.ts

app.ts A importação é feita Informando

entre chaves o que está sendo importado e depois dizemos ao interpretador aonde se encontra o

arquivo do módulo.

O caminho dos módulos podem ser relativos ou absolutos. O primeiro tipo usa três formas: O símbolo “./” identifica um módulo existente na mesma pasta que o arquivo que fez a importação. O símbolo “../” indica que o módulo está

em uma pasta anterior a do arquivo que importou o módulo. O uso do “/” indica que é a pasta raiz da aplicação.

O uso de caminho absoluto são feitos através da propriedade baseUrl no arquivo tsconfig.json.

import {Carro, printer} from './modelo1';

let uno = new Carro('Uno Hatch', 25000.00);

printer(uno);

Módulos

Exportando vários elementos

module1.ts

app.ts 1) O módulo expôs

dois elementos.

2) O arquivo principal está exportando dois elementos do módulo 1.

export class Carro{

constructor (public tipo: string, public valor: number){} }

export function printer(c: Carro){

console.log(`Carro: ${c.tipo} custa: ${c.valor}`) }

class Carro{

constructor (public tipo: string, public valor: number){} }

function printer(c: Carro){

console.log(`Carro: ${c.tipo} custa: ${c.valor}`) }

export {Carro, printer}

Módulos

No documento Introdução ao Typescript (páginas 66-90)

Documentos relacionados