Introdução ao Typescript
Introdução ao Typescript
• Linguagem criada e desenvolvida pela Microsoft de forma open source;
• Superset da linguagem Javascript (mantém a compatibilidade), em que a orientação a objetos e tipificação de valores assume um papel fundamental no aumento de
produtividade e na redução de erros associados à geração de código Javascript; • O Typescript depois de compilado gera código Javascript;
Introdução ao Typescript
• Qualquer ambiente Web que aceita Javascript irá aceitar Typescript. Site oficial da linguagem. Frameworks como Angular, Ionic e o NodeJS trabalham com Typescript
Introdução ao Typescript
• Possui uma sintaxe do tipo clássica referente aos conceitos de OO; • Permite herança, recurso não disponível em Javascrip clássico.
• Temos o conceito de módulos (pacotes, namespaces) também ausente em Javascript • Você não pode mexer na estrutura da classe sem receber um alerta;
• Existe o papel de construtores e pode-se inserir parâmetros opcionais (?). Vantagens
Introdução ao Typescript
• Mais algumas diferenças: Vantagens
Classe com propriedades automáticas Declaração automática
de propriedade, Basta usar o construtor para isso, aumentando a
produtividade.
Tipagem forte, depois de declarada, o tipo não
pode ser alterado, podendo assim ser verificado pelo compilador. Inferência de tipo, aonde o compilador define o tipo da variável.
Iremos usar o NodeJs, que é um servidor de aplicações web Javascript. O software
que iremos criar não precisará do Node e sim do browser e dos códigos. Mas
essa ferramenta é importante para o desenvolvimento. Por exemplo, fornecendo o NPM. Node.js e NPM
Gerenciador de pacotes Javascrip. Ou seja, acessamos um repositório de bibliotecas para projetos Javascript Node.js e NPM
Iremos usar essa ferramenta dentre as várias existentes para a
criação do código em Type Script
Visual Studio Code
Como instalar o Typescript
Slide 8
Como instalar o Typescript
• Lanch.json, task.json e tsconfig.json para fazer a instalação 1) Utilizamos o npm do compilador Typescript 2) Podemos testar a instalação requisitando a versão do programa. Instalando o compilador
Como instalar o Typescript
1) Crie uma pasta e faça o acesso
via VSCode.
2) Crie um arquivo com extensão “.ts” e digite o
código. Testando o VSCode e o compilador
3) Podemos usar o primeiro comando para compilar e o
segundo para rodar o arquivo “.js” criado. https://www.typescriptlang.org/play/ 4) Uma outra forma de testar é utilizando o compilador online da linguagem
Como instalar o Typescript
Testando o VSCode e o compilador
3) As propriedades significam respectivamente: Versão do compilador, Comando para compilação, exibir erros no console e, por último,
qual utilitário pode ser usado para apresentar soluções.
https://code.visualstudio.com/docs/typescript/typescript-compiling https://www.youtube.com/watch?v=Hs6XWwQUs_A
1) Para evitar os dois passos executados no slide anterior, usamos um recurso do VSCode chamado task runner, executamos o código através de uma tarefa, assim temos que criar um arquivo com os
passos que a ferramenta deve executar.
tasks.json 2) Crie uma pasta
”.vscode” e dentro dessa pasta um arquivos chamado tasks.json (Terminal >
Run Build Task...)
{ "version": "2.0.0", "tasks": [ { "type": "typescript", "tsconfig": "tsconfig.json", "problemMatcher": [ "$tsc" ], "group": { "kind": "build", "isDefault": true } } ] }
{ "compilerOptions": { "target": "es5", "module": "commonjs", "sourceMap": true } }
Como instalar o Typescript
Testando o VSCode e o compilador
2) As propriedades significam respectivamente: Versão do javascript, qual módulo padrão está
sendo utilizando e por isso, os arquivos de mapeamento para Debug devem ser gerados.
1) Agora temos que informar as configurações
do projeto em questão, para isso crie um arquivo chamado tsconfig.json na
raiz do projeto.
"version": "0.2.0",
"configurations": [ {
"type": "node",
"request": "launch",
"name": "Typescript debug",
"program": "${workspaceFolder}/app.ts", "outFiles": [ "${workspaceFolder}/**/*.js" ] }, { "type": "node", "request": "attach",
"name": "Attach to process",
"address": "localhost", "port": 5858, "outFiles": [ "${workspaceFolder}/**/*.js" ] } ] }
Como instalar o Typescript
Testando o VSCode e o compilador
2) Informe o nome do arquivo principal da aplicação.
1) Agora temos que informar as configurações
do projeto para Debug, para isso crie um arquivo
chamado laungh.json na pasta “.vscode”.
laungh.json https://code.visualstudio.com/docs/typescript/typescript-compiling
Como instalar o Typescript
Testando o VSCode e o compilador
2) Logo em seguinda executar com ou sem o DEBUG CRTL+F5 1) Depois de configurado, temos que compilar o script com os comandos
CRLT+SHIT+B.
• Veja um outro exemplo de código
Como instalar o Typescript
Crie um arquivo com extensão “.ts” e digite o
código. Testando o VSCode e o compilador
function teste(i: number){ var teste; if (i === 10){ valor = 20; } else { valor = 30; }
console.log(valor); }
• A declaração de variáveis em Typescript segue a mesma conversão do Javascript, o qual é feita através da palavra reservada “var”. Infelizmente as variáveis declaradas dessa forma estão sujeitas ao chamado hoisting. Veja exemplo:
Tipos básicos
Variáveis
function teste(i: number){
if (i === 10){ var valor = 20; } else { var valor = 30; }
console.log(valor); }
2) Esse código não implica em erro, a declaração da
variável com “var” é transferida para o início
do escopo com o valor “undefined” 1) Ocorre erro?
• O ECMAScript 2015 (ECMAScript 6 ou Javascript 6) introduziu novos termos – let e const que podem ser utilizados em substituição ao termo var;
consté usado para introduzir valores constantes
letnão está sujeito a hoisting. Todas as declarações com este termo possui o âmbito do bloco onde foram
utilizadas
Tipos básicos
Variáveis
function teste(i: number){
if (i === 10){ let valor = 20; } else { let valor = 30; }
console.log(valor);
• Os tipos básicos introduzido pelo Typescrip são semelhantes aos que podem ser usados em Javascript. O tipo boolean recebe os valaores true ou false.
Tipos básicos
Boolean
var isNew: boolean = false;
isNew = true;
• Todos os números são do tipo number, não existe subtipos como integer ou float. Number
var age: number = 21;
var pi: number;
• Sempre que necessitamos de um texto, recorrermos ao tipo string. Os valores literais podem ser delimitados por aspas duplas ou simples.
Tipos básicos
String
var nome: String = ‘Não informado’;
nome = "Luis";
• Valor literal delimitados por caractere de acento de crase (`) e permitem criar strings multilinha ou expressões com placeholders utilizando ${xxx} .
Template strings
let nome = "Luis";
let expressao = ` Olá, ${nome}
tudo bem com você?`;
var list1: number[] = [1, 2, 3];
let i:any;
for(i in list1) {
console.log(list1[i]) }
var list2: Array<number> = [8,12,33];
console.log(`Primeiro elemento da lista2 => ${list2[0]}`);
var list3: number[]
list3 = [5, 4, 3];
list3.forEach( (p) => console.log(p) );
var alpha = ["a", "b", "c"];
var numeric = ["1", "2", "3"];
var alphaNumeric = alpha.concat(numeric);
console.log("alphaNumeric : " + alphaNumeric );
alphaNumeric.push("098");
console.log("alphaNumeric : " + alphaNumeric );
• Existem também um tipo que armazena um conjunto de valores do mesmo tipo, matriz unidimensional, a qual pode ser declarado de duas formas diferentes:
Tipos básicos
Array Compilador exige que a variável seja do tipo any ou string. Acessando um elemento específico Inserindo um elemento no final do array.• Existem vários métodos para trabalhamos com arrays, pois eles são tratados como objetos pela linguagem:
Tipos básicos
Array
• Exemplos:
Tipos básicos
Array
https://www.tutorialspoint.com/typescript/typescript_arrays.htm
//---var marks:number[] = [58, 68, 74, 88, 64, 90]
function isPassed(element: number, index: number, array: number[]) {
return (element >= 35) }
var passed = marks.every(isPassed)
if(passed)
console.log("The student has passed.")
else
console.log("The student has failed")
//---function usaInformacao(value: number) {
console.log(value+100); }
var marks1:number[] = [58, 68, 74, 88, 64, 90]
var passA: boolean[];
marks1.forEach( n => usaInformacao(n));
// ou
// marks1.forEach(usaInformacao);
//---var numbers = [1, 4, 9];
var roots = numbers.map(n => Math.sqrt(n));
console.log("roots is : " + roots );
// ou
//var roots = numbers.map(Math.sqrt); //console.log("roots is : " + roots );
• Exercício:
1) Crie um array com notas de um aluno;
2) Filtre esse array para retornar somente as notas maiores que 60; 3) Nesse mesmo array, informe em qual posição aparece a nota 70.
Tipos básicos
Array
• Exercício - Solução:
Tipos básicos
Array
Tipos básicos
Exemplos com HTML https://www.tutorialspoint.com/typescript/typescript_arrays.htm <!DOCTYPE html> <html> <head><meta charset="UTF-8"> <title>
Introdução ao typescritp
</title> </head> <body>
<script type="module" src="app.js"></script> </body>
</html>
index.htm
let input = document.createElement('input');
input.setAttribute("id", "texto");
input.setAttribute("value", "Entre com o nome");
document.body.appendChild(input);
var campo: HTMLElement = document.getElementById('texto');
let button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
alert(‘Olá’);
if (campo !== null)
alert(campo.getAttribute("value")); }
• Existe uma especialização do tipo array que se chama tuple, esse tipo permite definir tipos de dados diferentes para diferentes posições do vetor:
Tipos básicos
Tupla
let tp : [string, number] = ['Jose', 10];
tp[0] = 'Tiao';
// tp[1] = 'Vieira'; <== Erro.
tp.push(100);
tp.push('Bruno');
tp.forEach((o) => console.log(o));
// tp[3] = true; <== Erro. A primeira e a segunda posição do array terão respectivamen te esses tipos. As demais posições podem assumir qualquer um dos dois
tipos (number ou string).
enum SinalSemaforo {
Verde = 1,
Amarelo = 2,
Vermelho = Verde | Amarelo
}
let sinalAtual = SinalSemaforo.Verde;
console.log(sinalAtual);
enum SinalSemaforo {
Verde = 1,
Amarelo = 2,
Vermelho= = 6
}
let sinalAtual = SinalSemaforo.Verde;
console.log(sinalAtual);
enum SinalSemaforo {
Verde,
Amarelo,
Vermelho
}
let sinalAtual = SinalSemaforo.Verde;
console.log(sinalAtual);
• Esse tipo de dado permite atribuir nomes amigáveis a valores numéricos constantes, assim temos uma lista com valores predefinidos, o uso desse tipo ajuda a melhorar a legibilidade do código.
Tipos básicos
Enum
Como não atribuímos explicitamente nenhum número aos elementos, o primeiro valor terá o numero zero, o segundo
um, e assim por diante
Fazendo a atribuição explícita de
valor.
Podemos calcular o valor, em relação aos outros
membros, nesse caso fazemos uma operação
lógica “ou” bit a bit.
sinalAtual = 2;
console.log(sinalAtual);
console.log(SinalSemaforo[sinalAtual]);
Podemos atribuir o valor inteiro diretamente. Podemos fazer a direção inversa na busca dos dados.
let notSure: any = 4;
notSure = "maybe a string instead";
console.log(notSure);
notSure = false;
console.log(notSure);
let qq: any = 10;
qq = "mudou";
console.log(qq.lenght);
let outro: Object = 10;
outro = "mudou";
console.log(outro.lenght); //<= Error: Property 'lenght' does not exist on type 'Object'.
•
Tipo introduzido pelo Typescript, geralmente, é utilizado quando não sabermos o
tipo do objeto referenciado por uma variável. Assim qualquer valor pode ser
atribuído a uma variável desse tipo.
•
Muitas vezes não podemos forçar o tipo do dado, talvez ele venha do banco ou
de uma API de terceiros. Qualquer que seja o motivo, você pode rotular sua
variável com o tipo "any", assim ela vai aceitar qualquer coisa.
Tipos básicos
Any A variável assume diferentes tipos ao longo do algoritmo.Poderíamos pensar que Any é igual a Object, já que esse último é o tipo base de todos os elementos em Javacript, porém, os métodos disponíveis para uso são do object e não os métodos dos tipos básicos
function warnUser(): void {
console.log("This is my warning message"); }
warnUser();
• Esse tipo é utilizado para significar a ausência de tipo. Tipicamente este termo é apenas usado na declaração de funções que não devolvem qualquer valor. O uso em variáveis não é útil porque apenas permite a atribuição dos valores undefined ou null
Tipos básicos
Void
Função sem retorno
let indefinido: undefined;
indefinido = undefined;
var a;
console.log(typeof a); //resultado> "undefined"
console.log(typeof a === "object"); //resultado> false
console.log(typeof a === "undefined"); //resultado> true
console.log(typeof a == "undefined"); //resultado> true
var b = null;
console.log(typeof b); //resultado> "object"
console.log(typeof b === "undefined"); //resultado> false
console.log(typeof b === null); //resultado> true
console.log(typeof b == null); //resultado> true
• São considerados subtipos de todos os outros tipos e podem ser utilizados na declaração de variáveis. Na prática, isto significa que estes valores podem ser atribuídos a qualquer tipo de variável , não sendo seu uso isolado muito importante.
• O valor undefined significa que a variável não teve valor associado a ela, enquanto null, as variáveis, funções, propriedades e métodos nativos dos quais se espera um objeto como valor ou retorno não foram entregues/atribuídos;
Tipos básicos
Null, Undefined
Podemos declarar uma variável do tipo
indefinido, mas não faz sentido, pois ele só
receberá esse valor. Variáveis não atribuídas são undefined Objetos não atribuídos são null
function func(a: number){
if (a === undefined)
console.log('variável não definida.’); }
var x: number;
func(x);
Exemplo de uso.
function geraErro(): never{
throw new Error("erro.") }
function Principal(){
geraErro(); }
//---function infiniteLoop(): never {
while (true) { }
}
• Esse tipo representa um valor que nunca acontece. Por exemplo, pode ser usado para dizer que uma função não devolve um valor, assim não precisamos do termo return. Assim como, null e undefined, ele é considerado como um subtipo de qualquer outro tipo.
Tipos básicos
Never
Função sem retorno
Função com retorno indefinido, mas nesse
caso também vai retornar never, pois é
fruto do fluxo da execução.
function efetua(opcao: string){
if (opcao === "opc1"){
return true;
} else if (opcao === "opc2"){
return true; } geraErro(); } Outro exemplo. Apenas uma observação, void e never tem conceitos diferentes. Exemplo de uso de “never”, indicando que a função não tem
• Usamos o tipo never para indicar funções sem retorno de execução ou para indicar que a função retorna uma exceção.
Tipos básicos
Never
Função sem retorno
O type void pode receber o valor null ou undefined e o type never não pode receber nenhum valor.
E para finalizar, quando não especificado um type nas funções do TypeScript, ele retorna um valor undefined.
let outroNome = "Jhony";
outroNome = 42; // <==Erro, tipo incompatível.
• É ideal indicar explicitamente o tipo das variáveis e objetos, contudo, quando a declaração de uma variável inclui a atribuição de um valor inicial, pode-se omitir a anotação do tipo.
Tipos básicos
Inferência de tipos
Variável do tipo string.
• Existem alguns cenários nos quais o programador está em melhor posição de saber que tipo específico é referenciado por uma variável. Um exemplo é uma hierarquia de classe. Essas conversões explicitas (cast ou assertions) são feitas de duas formas:
Conversão de tipo explícita
let someValue1: any = "this is a string";
let strLength1: number = (<string>someValue1).length;
let someValue2: any = "this is a string";
let strLength2: number = (someValue2 as string).length;
let someValue3: Object = "this is a string";
let strLength3: number = (<string>someValue1).length;
let someValue4: Object = "this is a string";
function dizOla(nome: string){
return `Olá, ${nome}`; }
let imprimeMsg = function (msg: string) : void {
console.log(msg); }
imprimeMsg(”teste!!”);
• Funções desempenham um papel importante em Typescript.
Funções
Funções nomeadas e anônimas
Função nomeada em que espera um valor string e retorna também um string. A linguagem aceita funções anônimas, para sua execução temos que associa-la a alguma variável.
(function() {console.log('anonima 1')})();
(function(a: number, b: number) {console.log(a+b)})(10,15);
Uma outra forma de execução é transformando a
função em uma expressão com os parênteses “()”.
O segundo par de parêntese indica o local para passar os parâmetros da função.
let impressora : (nome: string) => void;
impressora = function(info: string){
console.log(info); }
impressora("testando...");
• Funções podem ser usadas para definir novos tipos que, por sua vez, são utilizadas para tipificar outras variáveis ou parâmetros..
Funções
Especificação de tipo função
Definindo um tipo: Impressora é uma variável que espera uma referencia
para uma função que recebe uma string e não retorna valor.
Aqui temos a referencia para o
tipo de retorno.
Iniciando a variável com uma função válida para seu tipo.
Executa a função anônima sobre a variável impressora
var res = function (a: number, b: number) {
return a * b; };
console.log(res(12, 2));
Outro exemplo de função anônima.
function opcionais(nome: string, idade?: number){
if (idade == undefined)
console.log(`Olá ${nome}`);
else
console.log(`Olá ${nome}, você tem ${idade} anos.`); }
opcionais("Tião",22);
opcionais("Maria");
• Por padrão todos os parâmetros de uma função em Typescript são obrigatórios.
Contudo, podemos criar parâmetros opcionais utilizando o ponto de interrogação (?).
Funções
Parâmetros opcionais
Atenção: uma função pode definir vários parâmetros opcionais, devendo estes serem sempre colocados depois
dos parâmetros obrigatórios, se existirem. Marcamos o parâmetro como opcional. Chamada com dois e com um parâmetro.
function predefinidos (nome: string = "Raul", idade = 20){
console.log(`Nome: ${nome}, idade ${idade}`); }
predefinidos();
• Se for necessário, podemos atribuir um valor padrão para um parâmetro, Nesses casos, esse valor é utilizado no interior da função quando não atribuímos explicitamente um valor para parâmetro.
Funções
Parâmetros com valores predefinidos
Definindo valor padrão para os dois
parâmetros. Atenção: uma função pode definir
vários parâmetros com valores padrões, devendo estes serem sempre colocados depois dos parâmetros sem
function restParams(nome: string, ...outros:string[]){
return `Nome: ${nome} \n ${outros.join(' ')}`; }
console.log(restParams("Joe", "John", "Gilbert"));
console.log(restParams("Mary"));
function addNumbers(...nums:number[]) {
var i: number;
var sum:number = 0;
for(i = 0;i<nums.length;i++) {
sum = sum + nums[i]; }
console.log("sum of the numbers",sum) }
addNumbers(1,2,3)
addNumbers(10,10,10,10,10);
• A linguagem permite criar funções que esperam zero ou mais parâmetros de um determinado tipo. Esses parâmetros são chamados rest.
• Os parâmetros deste tipo são sempre representados por um array, para sua declaração temos que usar o caractere (...). Esse tipo de parâmetro tem que ser declarado no final da lista de variáveis.
Funções
Parâmetros REST
O programador pode optar por passar nenhum
parâmetro. Uso de parâmetro rest.
“join” cria ums string a partir de
let numeros = [1,2,3,4,5];
let aux1 = numeros.filter( function (valor, index, arr) {
return valor % 2 === 0} );
console.log(aux1.join(' '));
let aux2 = numeros.filter( (valor, index, arr) => valor % 2 === 0);
console.log(aux1.join(' '));
var foo1 = (x: number) => 10 + x
console.log(foo1(100))
var foo2 = function (x: number) { return 10 + x; };
console.log(foo2(100));
• Esse tipo de função é utilizado para facilitar a escrita de funções anônimas, ela é composta pela seção de parâmetros, o operador lambda (=>) e seu bloco de código (estrutura).
Funções
Funções arrows ou lambdas
Agora utilizamos o método filter do array passando uma função como
parâmetro. O primeiro exemplo mostra a forma convencional e o segundo usando funções arrow. Exemplo de criação e uso
de funções arrow. Logo abaixo, vemos a criação do
mesmo código sem o uso de funções lambdas.
var display = x => {
console.log("The function got "+x) }
display(12);
O uso do parêntese é opcional quando temos
• Exercício:
1) Crie uma função que recebe uma string e retorne a string com os caracteres separados por hífen. Exemplo: “Jose” => “J-o-s-e”;
2) Crie uma função que recebe uma string e retorna se ela é palindromo;
3) Crie uma função que recebe um array de string, retorne um array indicando se cada palavra é palindromo.
Tipos básicos
Funções
• Exercício - Respostas: 1)
2)
Tipos básicos
Funções
let soletrar = function (x: string): string{
x = x.replace("-","");
x = x.replace(" ","");
return x.toUpperCase().split("").join("-"); }
console.log(soletrar("Bruno Ferreira"));
console.log(soletrar("guarda-chuva"));
function isPalindromo(l) {
let x = l.split("").reverse().join("");
return (x == l) ? true : false; }
console.log(isPalindromo('casa'));
console.log(isPalindromo('oborobo'));
console.log(isPalindromo('asa'));
console.log(isPalindromo('babab'));
console.log(isPalindromo('Frango'));
Primeiro com a função split(), transformei um string em uma array, tendo uma array eu posso utilizar a função reverse(), que inverte a ordem dos elementos de uma array e por último utilizei a função join(), que junta os elementos de uma array em uma string.
Operador Descrição
+ Operador binário. Retorna a soma de dois números.
- Operador binário. Retorna a subtração de dois números.
* Operador binário. Retorna a multiplicação de dois números.
/ Operador binário. Retorna a divisão de dois números.
++ Operador unário. Adiciona um ao seu operando. Se usado como operador
prefixado (++x), retorna o valor de seu operando após a adição. Se usado como operador pós fixado (x++), retorna o valor de seu operando antes da adição.
-- Operador unário. Subtrai um de seu operando. O valor de retorno é análogo
àquele do operador de incremento.
% Operador binário. Retorna o inteiro restante da divisão dos dois operandos.
• Operadores aritméticos tomam valores numéricos (sejam literais ou variáveis) como seus operandos e retornam um único valor numérico.
Operadores
Operador Descrição
&& Operador retorna verdadeiro somente se toda a expressão for verdade.
|| Operador retorna verdadeiro somente se pelo menos uma expressão for
verdade.
! Operador retorna o inverso do valor inicial de uma expressão.
& Operador que executa uma operação bolleana do tipo (and) em cada bit dos
operandos informados.
| Operador que executa uma operação bolleana do tipo (or) em cada bit dos
operandos informados.
^ Operador que executa uma operação bolleana do tipo (Xor – ou excluisvo) em
cada bit dos operandos informados.
~ Operador que executa uma operação bolleana do tipo (not) em cada bit dos
operandos informados.
• Operadores lógicos são utilizados tipicamente com valores booleanos (lógicos); neste caso, retornam um valor booleano.
Operadores
Operador Descrição
= Operador de atribuição. Associa o valor da direita ao operando do lado
esquerdo.
+= Adiciona o valor do operando da direta com o da esquerda e atribui o resultado
no operando do lado esquerdo.
-= Subtrai o valor do operando da direta com o da esquerda e atribui o resultado
no operando do lado esquerdo.
*= Multiplica o valor do operando da direta com o da esquerda e atribui o
resultado no operando do lado esquerdo.
/= Adiciona o valor do operando da direta com o da esquerda e atribui o resultado
no operando do lado esquerdo.
• Um operador de atribuição atribui um valor ao operando à sua esquerda baseado no valor do operando à direita. O operador de atribuição básico é o igual (=).
Operadores
Operador Descrição
> Maior que (operando da esquerda é maior que o operador da direita).
< Menor que (operando da esquerda é menor que o operador da direita.
>= Maior ou igual a (operando da esquerda é maior ou igual ao operador da direita.
<= Menor ou igual a (operando da esquerda é menor ou igual ao operador da direita.
== Retorna verdadeiro caso os operandos tenham valores iguais.
!= Retorna verdadeiro caso os operandos não tenham valores iguais.
=== Retorna verdadeiro caso os operandos tenham valores e tipo iguais.
!== Retorna verdadeiro caso os operandos tenham valores ou tipos diferente.
• Um operador relacional compara seus operandos e retorna um valor lógico baseado em se a comparação é verdadeira.
Operadores
Relacionais Operadores aplicados ao Javascrip puro.• Alguns exemplos...
Operadores
• Interfaces permitem definir tipos que podem ser utilizados pelo compilador Typescript na validação do código, esse conceito define a estrutura do objeto;
• Interface pode ser vista como um contrato, ou seja, o formato de um novo tipo, caso uma declaração não esteja de acordo com a interface, um erro é lançado pelo
compilador.
• Como Javascript não tem suporte a esse recurso a definição da interface é ignorado quando o código é transcrito.
• Uma interface define uma coleção de propriedades e métodos, sem especificar os
detalhes de implementação associados a cada um desses membros. Esses detalhes são obrigação de um objeto ou uma classe que venha implementar a interface em questão. • Se um objeto ou classe que possuem os mesmos nomes, lista de parâmetros e tipos de
retorno que uma interface, então dizemos que são compatíveis.
Interface
• Para criar uma estrutura desse tipo, utilizamos a palavra reservada interface. Seguido pelo nome, sendo os seus membros definidos no interior de um bloco delimitado por chaves.
Interface
Sintaxe interface Pessoa { nome: String; imprime: () => void; }Para que algum tipo seja compatível com essa interface
ela tem que ter o mesmo atributo e
método.
function imprime(p: Pessoa){
if (!p.nome){
p.nome = 'Sem nome'; }
p.imprime(); }
Qualquer variável que tem a estrutura da interface poderá ser passada como
parâmetro nessa função.
interface LabelledValue {
label: string; }
function printLabel2(labelledObj: LabelledValue) {
console.log(labelledObj.label); }
let myObj2 = {size: 10, label: "Size 10 Object"};
printLabel2(myObj2);
function printLabel1(labelledObj: { label: string }) {
console.log(labelledObj.label); }
let myObj1 = {size: 10, label: "Size 10 Object"};
printLabel1(myObj1);
• Exemplo
Interface
Sintaxe
Uma alternativa ao uso de interface é declarar o
parâmetro como um objeto, nesse caso, todo
objeto que tenha a propriedade label do tipo
string pode ser passado como parâmetro.
Agora o mesmo exemplo é implementado com o uso
de interface, apesar de termos um código com mais linhas, a legibilidade
com o uso de interface é indiscutível.
interface SquareConfig {
color?: string;
width?: number; }
function createSquare(config: SquareConfig): { color: string; area: number } {
// ...
return null; }
let mySquare = createSquare({ colour: "red", width: 100 });
• Evitando erros
Interface
Sintaxe
Nesse exemplo, ocorreu um erro de digitação ao criar o object literal, em Javascript esse
erro seria imperceptível e ocorreria apenas em tempo de
execução. Mas com o uso de interface, o problema é apontado imediatamente.
function imprimir(p: OutraPessoa){
if (!p.nome){
p.nome = 'Sem nome'; }
if (p.imprime){
p.imprime(); } else {
console.log (`Sem membro imprime: ${p.nome}`); }
}
• Se for necessário, pode-se deixar um membro da interface como opcional através do caractere “?”.
Interface
Membros opcionais
Qualquer objeto que apresente uma
propriedade designada por “nome” é considerada compatível. Membros opcionais obriga-nos a ter algum cuidado na interação com objetos compatíveis. interface OutraPessoa { nome: String; imprime?: () => void; }
interface AlunoInterno{
readonly nome: string; }
let aluno: AlunoInterno = {nome: 'Jimy'};
aluno.nome = 'Jhon’; // Erro de compilação
• A linguagem suporta a criação de membros cujo os valores só podem ser alterados
durante a criação dos objetos que são compatíveis com a interface. Para isso, basta usar a palavra reservada readonly.
Interface
Membros somente leitura
Informando que o campo é somente leitura. Podemos atribuir o valor ao membro “nome” somente uma vez, a linha de baixo resultaria em
interface Pessoa {
nome: String;
imprime: () => void; }
interface Aluno extends Pessoa{
turma: string; }
• A linguagem suporta que uma interface estenda outra. Para isso tem-se que recorrer a palavra reservada extends.
Interface
Herança de interfaces
Uma variável que pertence ao tipo Aluno
terá as propriedades nome e turma, além do
método opcional “imprime” Uma interface pode herdar membros de várias outras interfaces usando a virgula (,) para declará-la.
• Primeiro vamos entender o que são objetos literais.
• Agora podemos analisar os erros de compatibilidades da linguagem entre literais e interfaces
interface Atendente{
nome: string; }
function imprimeNome(user: Atendente){
console.log(user.nome); }
imprimeNome({nome: 'Luiz', endereco: 'Rua 23’}); // Erro
var u: Atendente = {nome: 'Luiz', endereco: 'Rua 23’}; // Erro
var at1 = {nome: 'Luiz', endereco: 'Rua 23'};
imprimeNome(at1);
var u: Atendente = {nome: 'Luiz', endereco: 'Rua 23'} as Atendente;
var carro = {
marca: "Ford",
modelo: "Ka",
getDetalhes: function () {
return this.marca + ' - ' + this.modelo; }
}
Interface
Compatibilidade de interfaces com objetos literais
Como mecanismo de segurança, a atribuição de objetos literais diretamente a
parâmetros do tipo de uma interface, só é permitida se esse objeto definir apenas propriedades compatíveis com as da interface. Nesse exemplo a propriedade “endereço” não
existe na interface.
Literais são maneiras menores para definir objetos. Basta inserir entre chaves as propriedades e métodos de
um objeto. Nesse caso o objeto já é instanciado e referenciado pelo nome
da variável que ele foi atribuído.
Para burlar esse mecanismo de segurança, pode-se
usar uma variável auxiliar ou fazer uma
interface Existe{
(nome:string): boolean; }
let nomes = ['Rui','Jhon','Jimmy','Robert','Fancisca’];
let pesquisa: Existe = (n) => nomes.indexOf(n) >= 0;
console.log(pesquisa('Robert'));
console.log(pesquisa('Maria'));
• Vimos que interfaces descrevem a forma de objetos, Sendo as funções um objeto em Typescript, pode-se também definir funções através de uma interface.
Interface
Funções
2) Tipificamos uma variável que agora espera
uma função que é responsável por indicar
se um nome está presente em um array.
1) Nesse caso, a interface contém a assinatura do método
desejado. Nesse caso, uma função deve receber uma string
e retornar um boolean;
3) Ao definir a função, podemos usar outros nomes
para os parâmetros e não precisamos definir o tipo, pois
o compilador usa o tipo declarado na interface.
class Pessoa{
nome: String;
constructor(nome: string){
this.nome = nome; }
dizOla(){ console.log(`Olá ${this.nome}`)}; }
let n1 = new Pessoa('Tião');
• Javascript não tem suporte completo a orientação a objetos, na verdade a linguagem emula o conceito através de protótipo e das chamadas funções construtoras.
• A partir da ECMAScript 2015 foram introduzidos novos termos para que o código fique semelhante aos de linguagens tradicionalmente orientadas a objetos como C# e Java. • Typescript implementa as melhorias da nova versão de Javascript adicionando mais
recursos similares a linguagens OO e converte seus termos em código válido.
Classes
Introdução
1) Nome da classe
2) Definimos um construtor.
3) A classe tem uma propriedade e um método.
let m3: Pessoa = new Pessoa2('Robert');
class Pessoa{
public nome: String;
public constructor(nome: string){
this.nome = nome; }
public dizOla(){ console.log(`Olá ${this.nome}`)}; } 1) Podemos explicitar a visibilidade, mesmo que o padrão é public. class Pessoa2{
private nome: String;
constructor(nome: string){
this.nome = nome; }
dizOla(){ console.log(`Olá ${this.nome}`)}; }
let n2 = new Pessoa2('Tião');
n2.nome = 'teste'; // <- Erro.
• Por padrão todos os membros de uma classe são públicos. Mas ao contrário do Javascript, o Typescript suporta o uso de outros níveis de visibilidade.
Classes
Visibilidade
2) Esse membro só pode ser acessado dentro da classe.
3) Dois objetos são compatíveis quando os tipos, nomes e visibilidade das propriedades são os mesmo. Nesse caso, o
class Mamiferos{
constructor(private nome: string){ }
imprimirNome(){
console.log(`Olá ${this.nome}`) };
}
let gato = new Mamiferos('Chaninho.’);
gato.imprimirNome;
1) A classe tem a propriedade “nome”
que é privada.
• Existe um atalho que reduz o código necessário para declarar propriedades. Quando os parâmetros de um construtor tem anotados também os qualificadores, o compilador Typescrip injeta campos na classe com os mesmos nomes e qualificadores desses parâmetros.
Classes
class Aves{
private _nome: string;
constructor(nome: string){ this._nome = nome; }
get nome(){
return this._nome; }
set nome(nome: string){
if (!nome)
console.error('Erro. nome obrigatório’);
else
this._nome = nome; }
imprimirNome(){ console.log(`Olá ${this._nome}`)}; }
let ave = new Aves('Galinha');
ave.imprimirNome();
ave.nome = 'Faizão';
ave.imprimirNome();
1) Deve-se acessar as propriedades pelos nomes dos métodos.
Mas as métodos são acessados como
propriedades.
• As propriedades podem ser vistas como campos onde o acesso de leitura ou escrita é feito através do uso de métodos especiais.
Classes
Getters e Setters
1) Esses métodos acessam a propriedade _nome,
eles são uteis para proteger as variáveis
de atribuições incorretas.
class MembrosOpcionais{
nome: string;
idade?: number;
imprimeIdade?(): string; }
var mOp = new MembrosOpcionais();
if (mOp.imprimeIdade)
console.log(mOp.imprimeIdade)
2) Os membros opcionais podem retornar o tipo undefined, sendo assim, temos
que fazer o teste antes do uso dos métodos opcionais.
• Assim como as interfaces, os membros de uma classe podem ser opcionais, para isso usamos o caractere “?”.
Classes
Membros opcionais
1) O campo idade e o método são opcionais.
Como o método é opcional não precisa de
class Grid{
static Origem = {x: 0, y:0};
calculaDistancia(ponto: {x: number, y:number}){
let xD = (ponto.x - Grid.Origem.x);
let yD = (ponto.y - Grid.Origem.y);
return Math.sqrt(xD * xD + yD * yD); }
constructor (public escala: number){}; }
let distancia = new Grid(1).calculaDistancia({x:11, y:11});
console.log(distancia);
console.log(Grid.Origem.x);
2) Utilizamos o membro estático para calculo da distância, repare que o uso é feito através do nome da classe.
• Membros estáticos são compartilhados entre todas as instâncias criadas a partir de uma classe e acessadas através do nome da classe.
Classes
Membros estáticos 1) Declaramos um membro estático. 3) Mais um exemplo de uso de um membro estático.class Aluno extends Pessoa{
private _idade: number;
constructor(nome: string, idade: number){
super(nome);
this._idade = i; };
get idade(){
return this._idade; }
set idade(valor: number){
this.idade = valor; }
}
let aluno1 = new Aluno('Johny', 23);
aluno1.nome = 'Johny Lemos';
2) A classe é obrigado a invocar o construtor da classe pai através da palavra super.
• Técnica utilizada para obter reutilização de código e implementar o conceito de polimorfismo. Segue os mesmos padrões de linguagens OO e usa a palavra reserva
extends para a herança de código.
Classes
Herança 1) Herdamos os membros da classe Pessoa. 3) Podemos acessar os métodos públicos herdados pela classe.4) Seguindo os conceitos da OO clássica, pode-se declarar membros com encapsulamento
protected. Esse nível de acesso restringe a utilização dos membros somente à classe ou
abstract class Base{
nome: string;
abstract dizOla(); }
class Derivada extends Base{
dizOla(){
console.log('Ola!!!’); }
}
let derivada = new Derivada();
derivada.dizOla();
• Como na orientação a objetos clássica, em Typescript pode-se criar classes que não podem ser instanciadas diretamente. Essas classes servem apenas de padrão para as classes filhas, esse comportamento é alcançado através da palavra reservada abstract.
Classes
Classes abstratas 1) Não podemos instanciar objetos da classe abstrata. 3) Implementação do método abstrato. 2) Método que deve ser implementando pelas classes filhas.class Ponto{
x: number;
y: number; }
interface Ponto3d extends Ponto{
z: number; }
function imprimePonto(p: Ponto3d){
console.log(`Ponto x: ${p.x}, y ${p.y}, z ${p.z}`); }
let pTeste: Ponto3d = {x: 1, y: 2, z: 3};
pTeste.x = 10;
pTeste.y = 20;
pTeste.z = 30;
imprimePonto(pTeste);
• Comportamento que não é comum as linguagens OO tradicionais, as classes em
Typescript pode servir como tipo base de uma interface, parecido com uma herança. Ou seja, a interface herda os membros da classe.
Classes
Classes usadas como interface
1) A interface herda apenas a forma dos membros, ou seja, se a classe tiver algum método, a interface herda somente a assinatura do método, não a sua implementação.
2Acessando os três membros da
interface. Sendo que x e y foram
function padLeft(value: string, padding: string|number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value; }
if (typeof padding === "string") {
return padding + value; }
throw new Error(`Esperando string ou número: '${padding}'.`); }
let r = padLeft('Texto..',4);
console.log(r);
r = padLeft('Texto..','Inicio');
console.log(r);
• Typescript permite que um parâmetro ou uma variável assuma mais de um tipo. Esse conceito é chamado de união de tipos (“|”).
Outros tipo
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 comtipos 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
Instrução de exportação module1.ts 1) Podemos centralizar as exportações de elemento somente em uma linha. Instrução de exportação app.tsimport * as m1 from './modelo1';
let uno = new m1.Carro('Uno Hatch', 25000.00);
m1.printer(uno);
2) Podemos importar todos os elementos do
módulo, mas temos que dar um nome de acesso, nesse caso m1.
class Carro{
constructor (public tipo: string, public valor: number){} }
function printer(c: Carro){
console.log(`Carro: ${c.tipo} custa: ${c.valor}`) }
export {Carro, printer as printerLog}
Módulos
Renomeando os elementos
1) A função foi renomeada no comando de exportação.
import {Carro as Veiculo, printerLog} from './modelo1';
let uno = new Veiculo('Uno Hatch', 25000.00);
printerLog(uno);
2) A classe foi renomeada no comando de importação.
module1.ts