Prévia do material em texto
Programação cliente com TypeScript
Neste conteúdo, você vai aprender os conceitos e princípios de desenvolvimento da linguagem de
programação TypeScript. A linguagem de programação TypeScript é uma extensão da linguagem
JavaScript. Ambas têm o mesmo objetivo: desenvolver aplicações para web. Como era de se esperar, o
TypeScript oferece recursos mais avançados do que o JavaScript. Vamos desenvolver alguns exemplos
práticos que vão lhe ajudar a dominar os diversos aspectos da linguagem.
Prof. Sérgio Assunção Monteiro
1. Itens iniciais
Preparação
Tudo o que você precisa para rodar os exemplos é de um computador com acesso à internet e de um
navegador instalado, como o Google Chrome, por exemplo. Vamos rodar os exemplos no seguinte endereço
eletrônico: https://www.typescriptlang.org/play/index.html
Objetivos
Reconhecer os conceitos gerais e as similaridades com o JavaScript.
Descrever funções com TypeScript.
Analisar os tipos e narrowing.
Aplicar exemplos práticos de classes com TypeScript.
Introdução
Você consegue imaginar o funcionamento da nossa sociedade sem o uso das aplicações para internet?
A principal linguagem de programação que se popularizou para o desenvolvimento de aplicações para web foi
o JavaScript. E sua evolução foi a linguagem TypeScript, que possui os mesmos recursos, mas é superior em
relação ao suporte para uso de tipos e programação orientada a objetos.
Neste vídeo, apresentaremos os elementos essenciais da linguagem de programação TypeScript, bastante
utilizada no desenvolvimento de aplicações web tanto do lado do servidor, como do lado cliente.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
•
•
•
•
1. Conceitos gerais e similaridades com o JavaScript
Fundamentos do TypeScript
Agora, vamos conhecer os principais aspectos da linguagem de programação TypeScript, o que nos permitirá
criar bases sólidas para desenvolver aplicações mais completas.
Neste vídeo, apresentaremos os principais conceitos sobre os fundamentos da linguagem de programação
TypeScript e entender por que ela é tão importante para o desenvolvimento de aplicações web.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
O que é a linguagem de programação TypeScript?
TypeScript (TS) é uma linguagem de programação baseada na linguagem de programação JavaScript (JS). A
sua principal característica é a possibilidade de utilizar tipos estáticos, classes e interfaces. Confira alguns
aspectos fundamentais da linguagem:
Fortemente tipada
Orientada a objetos
Compilada
O TS foi desenvolvido pela Microsoft como resultado do trabalho de Anders Hejlsberg – que projetou a
linguagem de programação C#. Uma das definições muito comuns sobre o TS é que ele é um superconjunto
tipado e compilado de JS, e, na prática, é o JavaScript com recursos adicionais.
Recomendação
Em especial para os desenvolvedores de aplicações web, utilizar o TS traz vantagens no sentido de
construir aplicações mais tolerantes a falhas. Além disso, é um software de código aberto.
Atividade 1
Não há dúvidas de que a linguagem JavaScript (JS) é uma das mais importantes ferramentas para
desenvolvermos aplicações web. Ainda hoje, ela continua sendo muito utilizada na prática. No entanto, houve
uma extensão do JS para a linguagem TypeScript (TS). Obviamente, existem muitas semelhanças entre
ambas, mas, como era de se esperar, o TS acrescentou elementos novos como tipos e orientação a objetos
que são consideradas grandes vantagens. Nesse sentido, qual é um dos principais motivos do JS ainda ser
bastante utilizado?
A
•
•
•
Logotipo TypeScript.
O JS já possui muitos sistemas legados, além de que a curva de aprendizado para desenvolver aplicações
com ele é muito rápida.
B
O TS ainda é uma linguagem muito recente e suas vantagens não justificam a mudança da forma de
programar.
C
O TS permite desenvolver programação orientada a objetos e, isso, é bastante complexo na prática.
D
Para desenvolver uma aplicação no TS, são necessários passos muito complexos e muito diferentes do JS.
E
O TS ainda não é considerada uma linguagem de programação confiável e, na prática, ela é muito mais
limitada do que o JS para desenvolver aplicações web robustas.
A alternativa A está correta.
O TypeScript (TS) é uma extensão do JavaScript (JS). Na prática, tudo o que podemos fazer no JS também
podemos fazer no TS, mas o contrário já não é verdadeiro. O JS é muito usado, pois existem inúmeros
sistemas desenvolvidos nele e, apesar de utilizar conceitos mais simples, isso pode ser uma desvantagem,
pois pode ocasionar diversas vulnerabilidades, além de perdermos as vantagens dos recursos da
programação orientada a objetos suportada pelo TS.
JavaScript versus TypeScript: semelhanças e diferenças
Vamos conhecer os principais aspectos da linguagem de programação TypeScript, por meio de exemplos
simples, para assimilarmos como ela funciona.
Neste vídeo, apresentaremos algumas das principais semelhanças e diferenças entre as linguagens de
programação JavaScript e TypeScript. Na prática, vai ser natural que você use ambas para desenvolver as
suas aplicações extraindo, assim, o que cada uma oferece de melhor.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
JavaScript e TypeScript: pontos em comum
A origem do TypeScript está nas limitações do
JavaScript, pois o JavaScript foi desenvolvido
como uma linguagem de programação do lado
do cliente que passou a ser usado como uma
linguagem de programação do lado do servidor.
No entanto, ficou evidente que, à medida que o
código crescia, ele se tornava mais complexo e
difícil de gerenciar, o que impediu que o
JavaScript tivesse sucesso como uma tecnologia do lado do servidor. Por isso, então, houve a necessidade de
criar o TypeScript. Ambas as linguagens, naturalmente, têm muitas semelhanças, das quais podemos destacar
(FREEMAN, 2019):
O código de um projeto do TypeScript é convertido em código JavaScript simples, pois os browsers
não podem interpretá-lo de forma nativa. Isso significa que o código escrito em TypeScript é compilado
e convertido para JavaScript.
Qualquer código escrito em JavaScript pode ser convertido em TypeScript alterando a extensão de .js
(JavaScript) para .ts (TypeScritp), significando que JavaScript é TypeScript, visto que TS é um
superconjunto de JS.
Como consequência dos dois primeiros itens, o TypeScript pode ser compilado para ser executado em
qualquer navegador, dispositivo ou sistema operacional, ou seja, ele não é específico para nenhum
ambiente.
O TypeScript pode ser utilizado pelos desenvolvedores para usar código JavaScript já existente e incorporar
bibliotecas.
Diferenças entre JavaScript e TypeScript
Apesar das semelhanças entre as duas linguagens de programação, existem algumas diferenças marcantes.
Entre essas diferenças estão:
Atividade 2
Uma característica muito importante de qualquer solução de desenvolvimento é a capacidade de padronizar a
construção de uma solução. Normalmente, quem desempenha esse papel é o arquiteto de softwares. Nesse
sentido, assinale a alternativa correta de como o TypeScript (TS) se diferencia do JavaScript (JS) para
padronizar uma solução de desenvolvimento:
A
O TS obriga que o desenvolvimento de qualquer solução seja feita com programação orientada a objetos.
B
O TS é uma linguagem muito diferente da JS no sentido de implementar funções que devem ter uma
nomenclatura padronizada, caso contrário, o programa não funciona.
C
Para criarmos variáveis no TS, precisamos definir os tipos delas, senão os programas não funcionam.
D
Diferente do JS, o TS obriga que utilizemos um gerenciador de códigos que verifica se todos os programas
seguem o mesmo padrão de desenvolvimento.
E
•
•
•
TypeScript
É uma linguagem
de programação
orientada a
objetos.
Possui o
recurso de
tipos
estáticos.
Suporta interfaces
(recurso de
programação
orientada a objetos).
JavaScript
É uma
linguagem
de script.
Não possui o
recurso de
tipos
estáticos.
Não suporta
interfaceso parâmetro de tipo
genérico entre ente os símbolos “” (maior que) após o nome da classe. Uma classe
genérica pode ter atributos genéricos, como métodos.
Exemplo de classe genérica
Confira um exemplo que utiliza uma classe genérica. Nesse caso, o nome da classe genérica é “Estudante” e
os parâmetros genéricos são “U” e “T”.
Veja o código que utiliza a classe genérica:
typescript
class Estudante
{
private id: T|undefined;
private nome: U|undefined;
public set_valor(id: T, name: U): void {
this.id = id;
this.nome = name;
}
public exibir_dados():void {
console.log(`Id = ${this.id}, Nome = ${this.nome}`);
}
}
let estudante_01 = new Estudante();
estudante_01.set_valor(7709, "Isaac Newton");
estudante_01.exibir_dados();
let estudante_02 = new Estudante();
estudante_02.set_valor("9903", "Coraline");
estudante_02.exibir_dados();
Devemos notar que os tipos utilizados dentro da classe são definidos apenas quando um objeto é instanciado.
Observe a saída da execução do código:
plain-text
[LOG]: "Id = 7709, Nome = Isaac Newton"
[LOG]: "Id = 9903, Nome = Coraline"
Com isso, concluímos o nosso estudo sobre a linguagem TypeScript. Apesar de já termos destacado em
vários momentos a importância de executar esses códigos, reforçamos que a melhor forma de aprender uma
linguagem de programação é executando os exemplos e, a partir deles, fazer modificações e forçar situações
que possam levar a erros, pois, na prática, situações desse tipo vão acontecer com frequência e a melhor
maneira de estar preparado para tratá-las é já ter passado por casos semelhantes.
Atividade 4
Desenvolver um sistema vai muito além da codificação em uma sintaxe específica. Um exemplo concreto
dessa afirmação são as classes genéricas que, inclusive, são suportadas pela linguagem de programação
TypeScript (TS). Assinale a alternativa correta a respeito da importância do uso classe genérica no TS:
A
As classes genéricas são uma forma alternativa de se referenciar à propriedade de herança e, semelhante a
esta, ela tem a capacidade de estender seu comportamento às classes herdeiras.
B
A classe genérica garante que as classes herdeiras devem implementar, obrigatoriamente, os métodos dela.
C
A maior vantagem da classe genérica no TS é a clareza que ela oferece para o código, pois utiliza uma sintaxe
muito simples de trabalhar e documentar o sistema.
D
Uma das vantagens da classe genérica é a velocidade que ela oferece para a execução de um sistema, pois
ela utiliza os recursos de forma mais eficiente.
E
As classes genéricas podem ser usadas para garantir que todas as funcionalidades relacionadas estejam em
uma única classe facilitando, assim, a manutenção e segurança do código.
A alternativa E está correta.
Existem várias vantagens em trabalhar com classes genéricas no TS. Entre essas vantagens estão a
organização do código, pois todas as funcionalidades podem ficar centralizadas em apenas uma classe.
Assim, podemos garantir mais segurança para o sistema e reduzir as chances de inserir vulnerabilidades,
uma vez que a classe vai se adaptar ao tipo de dados que vamos passar para ela, mas manterá as mesmas
funcionalidades.
Aplicando herança
Vamos ver um exemplo de aplicação de herança e, em seguida, aplicaremos o conceito na especialização de
uma classe que modela veículos. Sua tarefa será modelar duas especializações da classe veículos: a primeira
especialização será veículos de carga (classe carga), na qual será inserido o atributo capacidade de carga; na
segunda, veículos de transporte de pessoal (classe carga), em que será inserido o atributo de número
máximo de passageiros.
Neste vídeo, apresentaremos a modelagem do uso de herança para especializar a classe aluno. Além disso,
você vai saber como modelar duas subclasses: aluno de graduação e aluno de pós-graduação.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Roteiro de prática
Confira a seguir, o passo a passo!
Passo 1: Abrir o ambiente de desenvolvimento.
Passo 2: Colar a classe veículo descrita no código a seguir.
typescript
class veiculo {
private renavam: string = ''; // default
private placa: string = '';
constructor(oRenavam: string, aPlaca: string) {
this.renavam = oRenavam;
this.placa = aPlaca;
}
public get_dados():void{
console.log('Dados do veículo: renavam = ${this.get_renavam()},placa = $
{this.get_placa()}');
}
public get_renavam = ():string => {
return this.renavam;
}
public get_placa = ():string => {
return this.placa;
}
}
Passo 3: Criar as subclasses pessoal e carga com: construtor, e o método get_dados que informará: renavam,
placa e carga ou renavam, placa e passageiros, conforme o caso.
Faça você mesmo!
A utilização de programação orientada a objetos no TypeScript permite combinar atributos e métodos em
uma unidade lógica chamada de classe. Por exemplo, vamos considerar o código a seguir:
typescript
class Conta {
private saldo:number=10;
getSaldo():number{
return this.saldo;
}
setDeposito=(valor:number):void=>{
this.saldo+= valor;
}
}
const c = new Conta();
c.setDeposito(10);
Nesse sentido, selecione a opção correta a respeito da implementação da classe Conta:
A
Para que a classe funcione corretamente é necessário implementar o construtor.
B
A execução do comando c.getSaldo() irá retornar o valor 20.
C
Como a classe não possui construtor, o atributo saldo recebe o valor inicial igual a 0 (zero).
D
O método setDeposito retorna um valor igual a 20.
E
É necessário usar o modificador public antes do método getSaldo.
A alternativa B está correta.
A classe está implementada corretamente e a chamada do método getSaldo vai retornar o valor 20, pois o
atributo saldo recebeu o valor 10, logo que o objeto c foi instanciado. Quando o método construtor não é
implementado explicitamente, o TypeScript utiliza uma implementação implícita do construtor.
5. Conclusão
Considerações finais
O que você aprendeu neste conteúdo?
Os principais conceitos do TypeScript.
Como desenvolver programas no TypeScript para realizar testes.
Como declarar tipos nas variáveis.
Como desenvolver funções no TypeScript.
A usar as funções da biblioteca RegEx no TypeScript.
A trabalhar com arrow functions.
A aplicar programação orientada a objetos (POO) no TypeScript.
Explore +
Acesse o site oficial do TypeScript, pesquise por “download” e aprenda como instalar o TypeScript na sua
máquina local, com uma sequência de passos.
Vá ao site oficial do nodejs e procure por procure por “Quick Start”. Lá, você vai encontrar diversos
exemplos de JavaScript e TypeScript que vão lhe ajudar a aprofundar mais os conhecimentos nessas
linguagens de programação.
Referências
ABREU, L. Typescript: o javascript moderno para criação de aplicações. Lisboa: FCA, 2017.
FREEMAN, A. Essential TypeScript. New York: Springer, 2019.
MICROSOFT. The Typescript Handbook. Consultado na internet em: 14 maio 2023.
•
•
•
•
•
•
•
•
•
Programação cliente com TypeScript
1. Itens iniciais
Preparação
ObjetivosIntrodução
Conteúdo interativo
1. Conceitos gerais e similaridades com o JavaScript
Fundamentos do TypeScript
Conteúdo interativo
O que é a linguagem de programação TypeScript?
Recomendação
Atividade 1
JavaScript versus TypeScript: semelhanças e diferenças
Conteúdo interativo
JavaScript e TypeScript: pontos em comum
Diferenças entre JavaScript e TypeScript
Atividade 2
Codificando uma aplicação com TypeScript
Conteúdo interativo
Como fazer testes rápidos de aplicações com TypeScript
Passo 1
Passo 2
Passo 3
Manipulação de variáveis string
Atividade 3
Utilização de comandos condicionais e iterativos
Conteúdo interativo
Trabalhando com comandos condicionais
Trabalhando com comandos iterativos
Atividade 4
Escrevendo o código de ordenação de um vetor em TypeScript
Conteúdo interativo
Roteiro de prática
Faça você mesmo!
2. Funções com TypeScript
Introdução às funções no TS
Conteúdo interativo
A importância das funções
Sintaxe básica
Funções sem retorno
Funções com retorno
Funções com parâmetros do tipo string
Atividade 1
Funções para manipulação de vetores e recursivas
Conteúdo interativo
Funções para manipular vetores
Funções recursivas
Atividade 2
Arrow functions
Conteúdo interativo
O que é uma arrow function
Funções com expressões regulares
Atividade 3
Expressões regulares mais interessantes
Conteúdo interativo
Roteiro de prática
Faça você mesmo!
Funções com parâmetros REST
Conteúdo interativo
REST na prática
Uso tradicional de uma função REST
Exemplo com arrow function
Arrow functions e RegEx: uma combinação poderosa
Atenção
Atividade 4
3. Tipos e narrowing
Os tipos estáticos do TypeScript e suas limitações
Conteúdo interativo
Definição de narrowing
Atenção
Parâmetro string
Parâmetro number
Parâmetro bigint
Parâmetro boolean
Parâmetro symbol
Parâmetro undefined
Parâmetro object
Parâmetro function
Narrowing confiável
Atividade 1
Narrowing através de Type Guards
Conteúdo interativo
Narrowing com if (refinamento)
Narrowing com switch
Atividade 2
Narrowing customizado
Conteúdo interativo
Roteiro de prática
Faça você mesmo!
4. Classes com TypeScript
Conceitos de programação orientada a objetos
Conteúdo interativo
O que é programação orientada a objetos?
Recomendação
Propriedades da POO
Encapsulamento
Herança
Polimorfismo
Atividade 1
As propriedades de encapsulamento e herança
Conteúdo interativo
Encapsulamento
Herança
Atividade 2
A propriedade de polimorfismo
Conteúdo interativo
Polimorfismo
Atividade 3
Classe genérica
Conteúdo interativo
Aspectos conceituais da classe genérica
Exemplo de classe genérica
Atividade 4
Aplicando herança
Conteúdo interativo
Roteiro de prática
Faça você mesmo!
5. Conclusão
Considerações finais
O que você aprendeu neste conteúdo?
Explore +
Referências(recurso de
programação
orientada a objetos).
• • • • • •
O TS oferece suporte para um tipo chamado de interface obrigando, assim, que as demais classes sigam um
determinado padrão de desenvolvimento.
A alternativa E está correta.
O TS oferece suporte para a programação orientada a objetos que, por si só, já é uma grande diferença e
vantagem em relação ao JS. Além disso, o TS oferece o tipo interface que estabelece um padrão de
desenvolvimento. Assim, todas as classes que vão implementar a interface são obrigadas a implementar os
métodos conforme estabelecido pela interface.
Codificando uma aplicação com TypeScript
Agora, vamos conhecer um dos ambientes de programação em que você vai testar rapidamente seus códigos
da linguagem de programação TypeScript e compartilhar com outras pessoas. Para isso, apresentaremos
como codificar uma aplicação.
Neste vídeo, apresentaremos um ambiente de programação que vai facilitar o teste dos seus programas em
JavaScript rapidamente. Além disso, demonstraremos o código que registra no log da aplicação a string “Hello
World”.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Como fazer testes rápidos de aplicações com TypeScript
Existem algumas formas de testar uma aplicação desenvolvida com TypeScript. Uma delas é fazer a instalação
local via npm. O passo a passo para esse tipo de instalação pode ser encontrado em: www.typescriptlang.org/
download.
Nesse trabalho, vamos executar nosso script on-line com o compilador oficial. Para isso, acesse o link:
www.typescriptlang.org/play/index.html.
Ao acessarmos esse endereço, veremos uma tela semelhante à seguinte:
Ambiente de desenvolvimento on-line do TypeScript.
Nesse ambiente, desenvolveremos todos os nossos exemplos. A seguir, apresentamos o código de “boas-
vindas” no TypeScript:
typescript
const mensagem = 'Boas-vindas Programador(a) FrontEnd!';
console.log(mensagem);
Agora, vamos selecionar esse código e copiá-lo para o ambiente on-line de desenvolvimento do TypeScript e,
em seguida, devemos pressionar o botão “Run”. Confira!
Passo 1
Escrever o código em TypeScript.
Passo 2
Pressionar o botão “Run” para executar o código.
Passo 3
É apresentada a saída da execução.
Esse ambiente é excelente para aprender a programar sem a necessidade de fazer instalações e
configurações locais. Além disso, temos a opção de compartilhar o projeto com outras pessoas. Para isso,
basta pressionar o botão “Share”, copiar o endereço que ele fornece e enviar para outras pessoas. Na imagem
a seguir, mostramos o processo.
Como compartilhar código on-line do TypeScript.
Os nossos próximos passos serão desenvolver vários exemplos que comparam as linguagens de programação
JavaScript e TypeScript.
Manipulação de variáveis string
Vamos iniciar o nosso processo de aprendizado com a utilização de variáveis do tipo string, que são cadeias
de caracteres. Primeiro, vamos ao código em JavaScript:
javascript
let vcadeiaJS = "Isto é um teste.";
console.log("Resultados com JavaScript");
console.log(vcadeiaJS);
Esse código produz como saída o seguinte resultado:
python
[LOG]: "Resultados com JavaScript"
[LOG]: "Isto é um teste."
Agora, vamos implementar uma versão semelhante para TypeScript:
typescript
let vcadeiaTS: string = "Isto é um teste.";
console.log("Resultados com TypeScript");
console.log(vcadeiaTS);
Cuja saída é:
plain-text
[LOG]: "Resultados com TypeScript"
[LOG]: "Isto é um teste."
As saídas dos dois códigos são semelhantes. Qual foi, então, a principal diferença entre ambos? A diferença
principal está na declaração da variável usada para armazenar a mensagem com os resultados. No caso do
TypeScript, tivemos que indicar que ela é do tipo string.
Atividade 3
Você já sabe executar uma aplicação no TypeScript. Considere o seguinte código em TS:
let vTS1: string = "F";
let vTS2: string = " G ";
let vTS3: string = "A";
console.log(vTS1+vTS2+vTS3);
Agora, execute o código. A saída será:
[LOG]: "F G A"
Nesse sentido, assinale a alternativa correta que modifique o código de tal forma que a saída seja:
[LOG]: "A F G"
A
let vTS1: string = "A";
let vTS2: string = " F ";
let vTS3: string = "G";
console.log("Resultados com JavaScript");
console.log(vTS2+vTS3+vTS1);
B
let vTS1: string = "A";
let vTS2: string = "F";
let vTS3: string = "G";
console.log("Resultados com JavaScript");
console.log(vTS1+vTS2+vTS3);
C
let vTS1: string = "A";
let vTS2: string = " F ";
let vTS3: string = "G";
console.log("Resultados com JavaScript");
console.log(vTS1+vTS2+vTS3);
D
let vTS1: string = "A";
let vTS2: string = "F";
let vTS3: string = "G";
console.log(vTS1+vTS2+vTS3);
E
let vTS1: string = "A";
let vTS2: string = " F ";
let vTS3: string = "G"
;console.log(vTS1+vTS2+vTS3);
A alternativa E está correta.
Esse exercício é muito importante, pois ele o ajuda a desenvolver o raciocínio lógico e observar a saída. De
fato, a saída solicitada pedia apenas o resultado: [LOG]: "A F G". Portanto, quaisquer outras saídas com
mensagens distintas dessas estão erradas.
Utilização de comandos condicionais e iterativos
Conheça agora a sintaxe e como utilizar os comandos condicionais e iterativos. Esses comandos são
utilizados para estabelecer o comportamento de um programa a partir da entrada de dados.
Neste vídeo, apresentaremos como trabalhar com os comandos condicionais e iterativos no TS. Eles
funcionam como o controle de fluxo da execução de um programa, a partir da entrada de dados.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Trabalhando com comandos condicionais
Agora que já aprendemos como declarar variáveis com tipos e utilizar os operadores lógicos e relacionais no
TypeScript, vamos ver como utilizar os comandos condicionais if-else. A ideia é bem simples: basicamente,
testamos se uma condição é verdadeira. Se ela realmente for verdadeira, então, o programa passa executar o
bloco de comandos associados ao comando if, senão ele vai para o comando else, caso esse seja utilizado no
programa (ABREU, 2017).
Confira um exemplo de como utilizar esses comandos condicionais:
typescript
let mediaFinal: number = 8.5;
if(mediaFinal == 10){
console.log("Resultado excelente!");
}else if(mediaFinal > 8){
console.log("Parabéns!");
}else if(mediaFinal >= 7){
console.log("Aprovado!");
}else{
console.log("vamos estudar mais!");
}
A saída resultante da execução do código é:
plain-text
[LOG]: "Parabéns!"
No TypeScript, podemos, ainda, utilizar o operador ternário, que tem a seguinte sintaxe: x = teste? valor1 :
valor2;
Ou seja, se o teste for verdadeiro, então, a variável x recebe o valor1, caso contrário, a variável x recebe
valor2.
Veja um exemplo de código que utiliza o operador ternário no TypeScript:
typescript
let podeVotar: string;
let idade: number = 17;
podeVotar = (idade maior){
maior = vetor[i];
}
}
console.log ("Forma 01: O maior elemento do vetor é:" + maior);
//forma 2: percorrendo os elementos do vetor
maior = vetor[0];
for(var val of vetor) {
if(val > maior){
maior = val;
}
}
console.log ("Forma 02: O maior elemento do vetor é:" + maior);
A execução do programa produz o seguinte saída:
plain-text
[LOG]: "Forma 01: O maior elemento do vetor é:40"
[LOG]: "Forma 02: O maior elemento do vetor é:40"
Agora, vamos analisar o comando while. Ele também tem duas versões: uma em que o teste é realizado antes
de entrar no bloco de comandos associados a ele e outra em que o teste só é realizado após a execução do
bloco de comandos.
Observe um exemplo com as duas versões do comando while:
typescript
let vetorw :number[] = [ 7, 5, 40, 20, 70, 50, 2, 1, 1];
let maiorw: number;
let i: number;
let tam:number = vetorw.length;
//forma 1: teste é realizado antes de entrar no bloco de comandos
i = 0;
maiorw = vetorw[0];
while(imaiorw){
maiorw = vetorw[i];
}
i++;
}
console.log ("Forma 01: O maior elemento do vetor é:" + maiorw);
//forma 2: teste é realizado depois de entrar no bloco de comandos
i = 0;
tam = vetorw.length;
maiorw = vetorw[0];
do{
if(vetorw[i]>maiorw){
maiorw = vetorw[i];
}
i++;
}while(i
A saída da execução desse código é dada por:
plain-text
[LOG]: "Forma 01: O maior elemento do vetor é:70"
[LOG]: "Forma 02: O maior elemento do vetor é:70"
Aqui, fechamos os conhecimentos básicos do TypeScript. Teste todos esses códigos e faça pequenas
modificações para analisar o comportamento deles. Mais adiante, vamos aprender alguns assuntos mais
avançados do TypeScript.
Atividade 4
Os comandos iterativos, tais como o “for”, fazem parte da sintaxe do TypeScript. Por exemplo, vamos
considerar o trecho de código a seguir:
plain-text
let v:number[]=[1,3,5,7,9];
let x:number=0;
for (var a of v) {
if(a%2==0){
x+=a;
}
}
console.log (x);
Agora, execute o código e, em seguida, selecione a opção correta com o valor da variável “x”:
A
1
B
0
C
4
D
10
E
20
A alternativa B está correta.
O trecho de código está correto. O que ocorre é que ele soma apenas os números divisíveis por 2, ou seja,
que são pares. Como o vetor "v" possui apenas números ímpares, o resultado da soma é "0".
Escrevendo o código de ordenação de um vetor em
TypeScript
Nesta atividade prática, escreveremos o código em TypeScript que ordena um vetor em ordem crescente.
Para demostrar a execução da atividade, apresentaremos o código que ordena um vetor em ordem
decrescente.
Neste vídeo, veremos o código de uma aplicação TS que ordena um vetor em ordem decrescente.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Roteiro de prática
Nesta atividade prática, você deverá codificar uma aplicação TypeScript que ordena um vetor em ordem
crescente, usando o método da bolha. Confira a seguir, o passo a passo!
Passo 1: Abrir o sítio “typescriptlang.org/play”.
Passo 2: Declarar um vetor de 10 posições, inicializando seu conteúdo com números inteiros aleatórios fora
de ordem.
Passo 3: Escrever o método da bolha em TypeScript. O algoritmo básico está codificado a seguir em
pseudocódigo:
typescript
troca = verdadeiro
enquanto (troca)
início
troca = falso
para i = 0 ate N-1 faça
início
se (vetor[i] > vetor[i+1])
inicio
troca = verdadeiro
aux = vetor[i]
vetor [i] = vetor[i+1]
vetor [i] = aux
fim
fim
fim
Passo 4: imprimir resultado
Faça você mesmo!
Em nossa atividade, declaramos um vetor pelo comando a seguir:
let vetorw :number[] = [ 7, 5, 40, 20, 70, 50, 2, 1, 1];
Essa forma de declaração remete a uma característica importante da linguagem TypeScript. Entre as
características apresentadas, destaque o principal conceito presente nesta declaração de variável:
A
TypeScript é orientada ao objeto.
B
TypeScript é uma linguagem interpretada.
C
TypeScript é uma linguagem do paradigma funcional.
D
TypeScript é uma linguagem do paradigma lógico.
E
TypeScript é uma linguagem tipada.
A alternativa E está correta.
Ao declararmos o vetor "vetorw", informamos ao ambiente de programação que os elementos do vetor
serão números. Isso faz da linguagem TypeScript, uma linguagem tipada.
2. Funções com TypeScript
Introdução às funções no TS
O TypeScript permite que possamos trabalhar com funções. Esse recurso é essencial para desenvolvermos
programas organizados, seguros, eficientes e fáceis de fazer manutenção.
Neste vídeo, apresentaremos como implementar funções no TypeScript. Esse é um recurso fundamental para
se tornar um desenvolvedor profissional.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
A importância das funções
As funções constituem unidades lógicas básicas de um código. Por meio delas garantimos que um programa
seja sustentável e reutilizável. Quando as utilizamos corretamente, podemos construir bibliotecas que
poderão ser utilizadas por vários programas. Uma consequência positiva imediata disso é a divisão de
trabalhos de uma equipe, pois pessoas com diferentes habilidades podem trabalhar em partes específicas do
desenvolvimento.
Os usuários das funções precisam conhecer as seguintes informações:
Quais são os argumentos de uma função.
Qual a saída que a função retorna, se é que ela deve retornar algum valor.
•
•
O usuário que vai consumir a função a enxerga como uma caixa-preta, por isso a responsabilidade de garantir
que funcione corretamente e com o melhor desempenho possível é do desenvolvedor.
Sintaxe básica
O TypeScript oferece suporte para funções. A sintaxe básica de uma função com o TypeScript é
(TYPESCRIPT HANDBOOK, 2022). Veja!
typescript
function nome_da_funcao(parâmetros: tipos) : tipos {
corpo da função;
return resultado; // caso a função tenha retorno
}
Apesar de essa ser a sintaxe mais comum, existem outras formas de programar uma função como veremos
adiante. A seguir, vamos conhecer as funções que não possuem retorno.
Funções sem retorno
Há situações em que não estamos interessados que a função tenha retorno. Nesse tipo de situação, a função
utiliza o tipo “void” para informar que não terá retorno.
Confira um código com exemplo de função que não possui retorno:
typescript
function imprimir_ts(msg: string, num: number): void {
console.log(`O conteúdo da variável mensagem é ${tmsg} e da variável numérica é $
{tnum}`);
}
let tnum: number = 10;
let tmsg: string = "este é um teste";
imprimir_ts(tmsg, tnum)
A função “imprimir_ts” recebe dois parâmetros, sendo um deles do tipo string e o outro do tipo number. Ela
simplesmente imprime os conteúdos dos parâmetros “msg” e “num”, como podemos ver a seguir:
plain-text
[LOG]: "O conteúdo da variável mensagem é este é um teste e da variável numérica é 10"
Agora, vamos estudar a forma mais comum de utilizar uma função, que é a aplicação de retorno.
Funções com retorno
Uma função omite do usuário a complexidade da lógica de programação. Assim, ousuário deve se preocupar
apenas com a passagem de parâmetros para a função e utilizar o retorno que ela produz.
Nesse caso, precisamos informar qual o tipo de retorno da função e utilizar, explicitamente, o comando
“return”.
Veja um exemplo de função com retorno:
typescript
function somar_ts(x: number, y: number): number {
return x + y;
}
let a: number = 10;
let b: number = 20;
let soma_ts = somar_ts(a, b);
console.log(`A soma de ${a} com ${b} é: ${soma_ts}`);
No caso, a função recebe dois parâmetros do tipo number, faz a adição deles e, em seguida, retorna o
resultado da adição para quem fez a chamada da função.
Observe a saída do código do exemplo:
plain-text
[LOG]: "A soma de 10 com 20 é: 30"
Funções com parâmetros do tipo string
Vamos ver mais um exemplo de função com retorno. Nesse caso, a função recebe dois parâmetros do tipo
string e retorna a concatenação deles, como podemos ver no código a seguir:
typescript
function concatenar_texto(x: string, y: string): string {
return x +", "+ y;
}
let t1: string = "primeiro";
let t2: string = "segundo";
let texto_concat = concatenar_texto(t1, t2);
console.log(`A concatenação de ${t1} com ${t2} é: ${texto_concat}`);
Observe o resultado da execução do programa:
plain-text
[LOG]: "A concatenação de primeiro com segundo é: primeiro, segundo"
Atividade 1
O TypeScript dá suporte ao uso de funções. Os parâmetros dessas funções possuem tipos e a própria função
também utiliza tipos para definir o retorno dela. Selecione a opção correta que justifica como uma vantagem a
forma como o TypeScript trabalha com funções:
A
O uso de funções elimina a possibilidade de erros em tempo de execução.
B
Ao utilizar tipos para os parâmetros das funções, o TypeScript acelera o desempenho de execução de um
programa.
C
A principal vantagem de utilizar tipos nos parâmetros das funções é a reutilização de código.
D
Com a utilização de tipos nos parâmetros das funções, o TypeScript possibilita trabalhar com vetores.
E
Usar tipos nos parâmetros auxilia a aplicação correta das operações que podem ser feitas com eles.
A alternativa E está correta.
A utilização de tipos nos parâmetros de uma função que o TypeScript suporta é uma vantagem no sentido
de auxiliar o controle das operações que podem ser realizadas com determinada variável.
Funções para manipulação de vetores e recursivas
Existem muitos usos comuns para funções. Um deles é a manipulação de vetores; outro é para trabalhar com
recursividade, ou seja, quando a função faz chamadas a si mesma.
Neste vídeo, apresentaremos como desenvolver funções para manipular vetores e como fazer chamadas
recursivas.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Funções para manipular vetores
Como vimos, vetores são estruturas de dados que permitem manipularmos diversos elementos através de
uma mesma variável com o uso de índices. Portanto, é natural trabalharmos com vetores nas funções. Passar
um vetor como parâmetro para uma função é semelhante ao que fizemos com os outros tipos de elementos,
ou seja, precisamos colocar o tipo de dado e utilizar os colchetes.
Veja um exemplo de como passar um vetor como parâmetro de uma função:
typescript
function somatorio(pvetor: number[]): number {
let soma: number = 0;
for (var val of pvetor) {
soma += val;
}
return soma;
}
let vetor: number[] = [1, 2, 3, 4, 5];
let res_soma: number = somatorio(vetor);
console.log(`O resultado do somatório dos elementos do vetor ${vetor} é: ${res_soma}`);
A função “somatorio” faz a soma de todos os elementos do vetor numérico. Para acessar cada elemento do
vetor dentro da função, utilizamos o comando iterativo “for”. O resultado da execução do exemplo é dado por:
plain-text
[LOG]: "O resultado do somatório dos elementos do vetor 1,2,3,4,5 é: 15"
Funções recursivas
Há situações em que podemos descrever um problema em termos dele mesmo. O exemplo clássico para esse
tipo de situação ocorre com o cálculo do fatorial de um número n que é dado por:
Observe a implementação para calcular o fatorial de um número n com uma função no TypeScript:
typescript
function fatorial(n: number): number {
if((n == 0)||(n == 1)){
return 1;
}
return n*fatorial(n-1);
}
let numero: number = 5;
let res_fat = fatorial(numero);
console.log(`O fatorial de ${numero} é: ${res_fat}`);
A saída da execução desse código é dada por:
python
[LOG]: "O fatorial de 5 é: 120"
Importante: Utilizar recursividade é muito útil em algumas situações, mas sempre devemos ficar atentos ao
caso base, pois ele garante que a função vai parar de fazer chamadas a si mesma.
Atividade 2
Questão 1
Uma das possibilidades de desenvolver funções no TS é através da recursividade. Há situações em que esse
tipo de programação é muito útil, mas existem alguns elementos básicos que o desenvolvedor não pode
deixar de fazer, caso contrário, terá problemas. Assim, assinale a alternativa correta a respeito dos aspectos
básicos de uma função recursiva:
A
Toda função recursiva deve ter um caso base em que ela termina, além da chamada a si mesma dentro da
própria função.
B
O programador é obrigado a declarar os tipos de todas as variáveis que ele for usar na função recursiva.
C
O uso de funções recursivas deve ser evitado no TS, pois afeta drasticamente o desempenho do sistema.
D
É essencial que o desenvolvedor documente a função recursiva no TS, caso contrário, o sistema não vai
permitir que ela funcione.
E
O programador não pode esquecer de estabelecer uma quantidade máxima de chamadas para a função
recursiva, afim de evitar loops infinitos.
A alternativa A está correta.
A recursividade é um recurso de programação muito útil. Nas aplicações web, a recursividade pode nos
ajudar a verificar padrões com poucas linhas de código e de uma forma natural que, de outro modo, seria
bastante complexo. No entanto, o programador não pode se esquecer de implementar o caso base, pois
ele garante o término do programa, nem a chamada para a própria função que é o que caracteriza a
chamada recursiva.
Arrow functions
As chamadas arrow functions são uma implementação prática do paradigma de programação funcional. Elas
são muito utilizadas na prática por programadores avançados, pois facilitam a manipulação de listas e torna o
código mais eficiente.
A linguagem de programação TypeScript pode utilizá-las e, com o tempo, você vai optar por trabalhar com
elas tanto pelo desempenho que oferecem, como pela elegância do código. Além disso, também vamos
explorar algumas das funcionalidades do pacote RegEx.
Neste vídeo, apresentaremos algumas formas avançadas de utilizar funções no TypeScript. Em especial,
vamos dar destaque para as arrow functions e a biblioteca RegEx.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
O que é uma arrow function
Nos códigos mais avançados do TypeScript, é muito comum utilizarmos funções lambda, que são estruturas
lógicas de programação funcional. A sintaxe desse tipo de função utiliza uma seta, que é a sintaxe abreviada
para definir a função anônima.
Essa espécie de função é conhecida como função seta, ou,de forma mais comum, como arrow function.
Entre as implicações práticas de utilizá-las estão a eliminação da necessidade de escrever a palavra-chave
“function” e fazer a associação da função a uma variável.
Veja dois exemplos de como utilizar uma arrow function:
typescript
let soma_anom_ts_1 = (x: number, y: number): number => {
return x + y;
}
let soma_anom_ts_2 = (x: number, y: number):number => x + y;
let c: number = 10;
let d: number = 20;
console.log(`Teste 01: a soma de ${c} com ${d} é: ${soma_anom_ts_1(c,d)}`);
console.log(`Teste 02: a soma de ${c} com ${d} é: ${soma_anom_ts_2(c,d)}`);
Na função “soma_anom_ts_1”, utilizamos a delimitação de blocos com os símbolos de abre parênteses e fecha
parênteses, além de utilizarmos a plavra-chave return.
Na função “soma_anom_ts_2”, não fizemos uso dos delimitadores de bloco e nem da palavra-chave return e,
ainda assim, obtivemos os mesmos resultados, como podemos ver a seguir:
plain-text
[LOG]: "Teste 01: a soma de 10 com 20 é: 30"
[LOG]: "Teste 02: a soma de 10 com 20 é: 30"
Funções com expressões regulares
A utilização de expressões regulares é um conhecimento essencial quando trabalhamos com
desenvolvimento de aplicações web, como para buscar por padrões em textos. Por meio dessas funções,
podemos procurar por substrings dentro de outras.
Observe um exemplo de uso de expressões regulares no TypeScript:
typescript
function checar_padrao(par_padrao: RegExp, par_texto: string): string {
if(par_padrao.test(par_texto)){
return "Foi detectado o padrão dentro do texto"
}
return "Não foi detectado o padrão dentro do texto";
}
const texto_teste : string = "O objetivo desse texto é realizar testes";
const padrao_regex : RegExp = /te/;
let res_teste: string = checar_padrao(padrao_regex, texto_teste);
console.log(`O resultado da execução do regex foi: ${res_teste}`);
Para utilizar uma expressão regular, precisamos indicar que o tipo de dado da variável é “RegExp”. No caso do
exemplo, o padrão que estamos procurando é a palavra “te” dentro do texto de teste. A seguir, apresentamos
o resultado da execução do programa:
plain-text
[LOG]: "O resultado da execução do regex foi: Foi detectado o padrão dentro do texto"
Atividade 3
Questão 1
O TypeScript dá suporte ao uso de função anônimas, também conhecidas como arrow functions. Por
exemplo, vamos considerar o trecho de código em que x deve ser, obrigatoriamente, maior do que 1:
let r = (x: number):number ⇒ x==1? 1:x+r(x-1);
console.log(r(8));
Selecione a opção correta que possui um código com uma lógica equivalente:
A
function r2(n: number): number {
return 36;
}
B
function r1(n: number): number {
return (1+n)*n/2;
}
C
let r3 = (x: number):number => 36;
D
function r4(n: number): number {
if(n%2==0){
return 36;
}
return 0;
}
E
let r5 = (x: number):number ⇒ x%2==1? 0:36;
A alternativa B está correta.
Apesar de todos os códigos retornarem o mesmo valor passando como parâmetro o valor "8", o único que
é equivalente ao código do exercício é o da função "r1". Para verificar isso, basta testar a chamada para
outros valores, com "5", "9" e "20", por exemplo. Para esses exemplos, apenas a função "r1" produzirá os
mesmos valores da função "r".
Expressões regulares mais interessantes
O pacote RegEx oferece diversas funcionalidades, facilitando o desenvolvimento de uma aplicação que
precisa manipular dados. Em especial, isso é bastante útil, quando esses dados têm algum tipo de padrão.
Agora, vamos estudar um exemplo que nos mostra o potencial do que podemos fazer com RegEx.
Neste vídeo, apresentaremos um exemplo bastante interessante de como podemos usar as funcionalidades
biblioteca RegEx para resolver problemas reais.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Roteiro de prática
Usando a função a seguir, o conceito de expressão regular e o roteiro apresentado no vídeo, reconheça e
imprima os códigos de rastreamento dos Correios brasileiros válidos. Os códigos têm a seguinte regra de
formação: duas letras, seguido de nove dígitos e a sigla “BR”.
typescript
function checar_todas_palavras(par_padrao: RegExp, par_texto: string[]): number {
let total: number = 0;
for (var val of par_texto) {
if(par_padrao.test(val)){
total++;
}
}
return total;
}
Confira a seguir, o passo a passo!
Passo 1: Copiar a função dada para o ambiente de desenvolvimento, alterando-a de modo a imprimir um
código de rastreamento válido.
Passo 2: Criar a expressão regular que reconhece o padrão de códigos de rastreamento dos Correios.
Passo 3: Criar um vetor de strings com os candidatos a código de rastreamento.
Passo 4: Chamar a função que irá imprimir os códigos válidos.
Faça você mesmo!
A biblioteca RegEx é utilizada em diversas linguagens de programação. Ela é um poderoso recurso para
manipular cadeias de palavras para identificarmos padrões, e realizar outras funcionalidades. Nós também
podemos usar RegEx no TypeScript. Assinale a alternativa correta com a expressão RegEx capaz de
identificar o seguinte padrão: o código do estado - separado entre parênteses e começando com zero –
seguido por nove dígitos numéricos, sendo que estão separados de 5 e 4 através do símbolo “-”. Exemplo:
(095)11111-1111
A
B
C
D
E
A alternativa D está correta.
Essa questão é muito importante para você desenvolver as habilidades de trabalhar com a biblioteca
RegEx. É necessário realizar alguns testes no ambiente de programação do TypeScript para chegar à
conclusão correta.
Funções com parâmetros REST
Em algumas situações, quando trabalhamos com aplicações web, é comum não sabermos com antecedência
a quantidade de parâmetros que uma função do nosso sistema vai receber. Para isso, o TypeScript oferece
funções com parâmetros REST, que nos permite lidar com essas situações.
Neste vídeo, apresentaremos um exemplo de como utilizar parâmetros REST para lidar com situações nas
quais a função não conhece de anteriormente a quantidade de parâmetros que ela vai receber.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
REST na prática
Esse tipo de função permite receber uma quantidade não definida de parâmetros. Ela é muito útil para
aplicações web. A sintaxe dela é caracterizada pelo uso de três pontos logo depois de algum parâmetro.
Uso tradicional de uma função REST
Nesse caso, temos um exemplo de uma chamada tradicional com exceção do uso dos “três pontos” na
passagem de parâmetro da função, conforme podemos ver no código:
typescript
function saudar_pessoas(saudacao: string, ...nomes_pessoas: string[]) {
return saudacao + " " + nomes_pessoas.join(", ") + "!";
}
let msg1: string = saudar_pessoas("Bom dia!", "Alunos", "Alunas");
let msg2: string = saudar_pessoas("Bom dia!", "Alunos", "Alunas", "Professoras",
"Professores");
console.log(`Primeira saudação: ${msg1}`);
console.log(`Segunda saudação: ${msg2}`);
Cuja saída é dada por:
plain-text
[LOG]: "Primeira saudação: Bom dia! Alunos, Alunas!"
[LOG]: "Segunda saudação: Bom dia! Alunos, Alunas, Professoras, Professores!"
Exemplo com arrow function
Agora, vamosver outra versão que resolve a mesma situação, com a utilização de arrow function no código a
seguir.
typescript
let saudar_pessoas_af = (saudacao: string, ...nomes_pessoas: string[]) => {
return saudacao + " " + nomes_pessoas.join(", ") + "!";
}
let msg1_af: string = saudar_pessoas_af("Bom dia!", "Alunos", "Alunas");
let msg2_af: string = saudar_pessoas_af("Bom dia!", "Alunos", "Alunas", "Professoras",
"Professores");
console.log(`Primeira saudação: ${msg1_af}`);
console.log(`Segunda saudação: ${msg2_af}`);
Cuja saída é dada por:
python
[LOG]: "Primeira saudação: Bom dia! Alunos, Alunas!"
[LOG]: "Segunda saudação: Bom dia! Alunos, Alunas, Professoras, Professores!"
Arrow functions e RegEx: uma combinação poderosa
As saídas das duas versões são semelhantes, como era de se esperar. O ponto fundamental que precisamos
notar é que utilizamos as mesmas chamadas da função, mas quantidades diferentes de parâmetros. Isso se
aplica muito bem em situações nas quais queremos generalizar tratamentos de dados sem a necessidade de
implementar diversas funções para cada situação.
Atenção
Nesse caso, se essa utilização não for bem-organizada, será difícil dar manutenção no código.
Agora que já conhecemos os aspectos fundamentais do TypeScript e sabemos as diversas formas de
criarmos e utilizarmos funções, vamos aprofundar os aspectos mais avançados da linguagem, como o
conceito de narrowing, que oferece mais flexibilidade na programação.
Antes, porém, fica a sugestão: execute todos os códigos que viu até agora. Faça pequenas alterações e
estude os resultados. Também crie situações para gerar erros, pois é uma boa forma de aprender mais sobre
a linguagem.
Atividade 4
Aprendemos sobre as funções REST e arrow functions no TypeScript (TS). Ambas podem ser usadas em
diferentes momentos e, de fato, tornar a programação mais vantajosa. Nesse sentido, assinale a alternativa
correta a respeito das vantagens de utilizar funções RegEx e arrow functions no TS:
A
Ambas as funções são modernas e, por isso, devem ser usadas com frequência.
B
Tanto as funções da biblioteca RegEx, como as arrow functions possuem mecanismos de segurança que
eliminam riscos com falta de segurança.
C
O TS obriga que os desenvolvedores utilizem as funções da biblioteca RegEx e as arrrow functions.
D
A biblioteca RegEx, por si só, possui funções muito lentas que são otimizadas com o uso das arrow functions.
E
Elas são otimizadas para gerenciar os dados com mais eficiência, além de oferecerem flexibilidade.
A alternativa E está correta.
As funções da biblioteca RegEx são extremamente úteis para manipular listas de forma eficiente através de
pouco código, mas que exige que conheçamos bem a sintaxe dela. Já as arrow functions oferecem muita
flexibilidade de programação, além de terem melhor desempenho na prática do que as funções tradicionais.
3. Tipos e narrowing
Os tipos estáticos do TypeScript e suas limitações
O TypeScript oferece um recurso chamado de narrowing, o qual permite que a mesma função tenha um
comportamento distinto no momento da passagem de parâmetros. Isso pode ser vantajoso no ambiente de
desenvolvimento web.
Neste vídeo, apresentaremos o conceito de narrowing no TypeScript e aprenderemos a identificar o tipo de
dado com o qual está trabalhando.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Definição de narrowing
Narrowing, traduzido para o português, significa estreitamento, e é um recurso que o TypeScript oferece
como um modo de seguir possíveis caminhos de execução quando uma função recebe um parâmetro, ou
mesmo quando declaramos uma variável. A ideia é que uma variável possa ter o seu tipo definido durante a
execução do programa. Para fazer isso, precisamos indicar quais são os possíveis tipos que ela pode assumir
(TYPESCRIPT HANDBOOK, 2022).
Atenção
Há um ponto relevante para levarmos em consideração aqui. Como os tipos das variáveis serão
definidos durante a execução, então precisamos verificar em que tipo a variável está operando, pois não
podemos utilizá-las da mesma maneira.
Para tratar essa situação o TypeScript utiliza um recurso chamado “Type Guard” – é traduzido para o
português como tipos protegidos. O objetivo desse recurso é verificar qual o tipo em que a variável está
operando através do operador typeof.
Vamos ver, agora, alguns exemplos de como utilizar o operador typeof com os tipos de variáveis.
Parâmetro string
Neste exemplo, para testar se o parâmetro é do tipo string, precisamos realizar o seguinte teste:
typescript
if(typeof parametro === "string") {
// Realizar alguma operação com o parâmetro
}
Parâmetro number
Utilizamos tipos numéricos com bastante frequência em aplicações desenvolvidas com TypeScritp. A sintaxe
é dada por:
typescript
if(typeof parametro === "number") {
// Realizar alguma operação com o parâmetro
}
Parâmetro bigint
O tipo bigint é utilizado em situações nas quais precisamos manipular números inteiros muito grandes, como
identificadores de banco de dados, e situações em que precisamos manipular data e hora. A sintaxe para
testar se um parâmetro é do tipo bigint é dada por:
typescript
if(typeof parametro === "bigint") {
// Realizar alguma operação com o parâmetro
}
Parâmetro boolean
Utilizar variáveis lógicas é muito comum, pois, constantemente, deparamo-nos com situações que exigem
testes. A sintaxe para testar se uma variável é do tipo lógico é dada por:
typescript
if(typeof parametro === "boolean") {
// Realizar alguma operação com o parâmetro
}
Parâmetro symbol
Symbol é um tipo primitivo do TypeScript, útil para criarmos símbolos que serão utilizados para controlar os
possíveis valores de uma variável. A sintaxe para testar se uma variável é do tipo symbol é dada por:
typescript
if(typeof parametro === "symbol") {
// Realizar alguma operação com o parâmetro
}
Parâmetro undefined
Quando um tipo não é definido, o TypeScript utiliza o undefined. A sintaxe básica para testar se uma variável
undefined é:
typescript
if(typeof parametro === "undefined") {
// Realizar alguma operação com o parâmetro
}
Parâmetro object
Há situações em que trabalhamos com dados complexos. Nesse caso, utilizamos o tipo object do TypeScript,
cuja sintaxe é dada por:
typescript
if(typeof parametro === "object") {
// Realizar alguma operação com o parâmetro
}
Parâmetro function
Uma das implicações de utilizar arrow funtions é que podemos passá-las como parâmetros para outras
funções. Para testar se um parâmetro é do tipo function, utilizamos a seguinte sintaxe:
typescript
if(typeof parametro === "function") {
// Realizar alguma operação com o parâmetro
}
Narrowing confiável
O TypeScript oferece diversos recursos para trabalhar com narrowing. Um desses recursos é a utilização do
símbolo “?” (interrogação) para verificar se uma variável é realmente confiável.
Veja um exemplo de como isso funciona na prática:
typescript
function testar_confianca(x: number, y?: number):number {
return x + (y ?? 10);
}
let x1: number = testar_confianca(1, 9);
let x2: number = testar_confianca(1);
let x3: number = testar_confianca(1, undefined);
console.log(`Teste 1: ${x1}`);
console.log(`Teste 2: ${x2}`);
console.log(`Teste 3: ${x3}`);
O parâmetro “y” da função está escrito “y?” que já indica para o TypeScript que deve ser verificado se ela éou não confiável. Além disso, no retorno da função é utilizado “??” que indica que se a variável “y” não for
confiável, então, deve ser somado o valor “10” à variável “x”.
Confira a saída da execução do código:
plain-text
[LOG]: "Teste 1: 10"
[LOG]: "Teste 2: 11"
[LOG]: "Teste 3: 11"
Atividade 1
Uma das características que distingue o TypeScript de outras linguagens de programação é o suporte para
narrowing. Há situações nas quais utilizar o narrowing oferece vantagens. Selecione a opção correta que
apresenta uma dessas situações:
A
Eliminar erros de tipos de dados.
B
Acelerar o desempenho da execução das funções.
C
Implementar funções compatíveis com o JavaScript.
D
Garantir a flexibilidade e reutilização de código.
E
Trabalhar com vetores heterogêneos.
A alternativa D está correta.
A utilização de narrowing no TypeScript oferece flexibilidade do código, pois é possível verificar qualquer
tipo, incluindo tipos personalizados pelo desenvolvedor. Além disso, também auxilia na reutilização das
funções, pois permite que combinemos vários tipos de dados dentro da mesma função.
Narrowing através de Type Guards
Apesar de o narrowing ser um recurso interessante em alguns casos, precisamos ter formas de identificar a
que tipo o dado se refere e como devemos tratá-lo. Felizmente, o TypeScript oferece esse recurso através
dos Type Guards.
Neste vídeo, apresentaremos como utilizar os Type Guards do TypeScript para se prevenir de erros em tempo
de execução devido à passagem de parâmetros para funções.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Narrowing com if (refinamento)
A forma mais comum de utilizarmos o narrowing em uma função é definir nos parâmetros quais são os
possíveis tipos que a função pode assumir com o auxílio do símbolo “|” (barra vertical).
Veja um exemplo no qual o parâmetro da função pode ser do tipo “number”, ou “string”. O operador “typeof” é
usado para garantir a proteção do tipo.
typescript
function func_testar_if(par_valor: number|string): number {
if (typeof par_valor === 'number') {
return par_valor;
}
if (typeof par_valor === 'string') {
return par_valor.length;
}
throw new Error('O parâmetro possui um tipo que não é suportado: ' + par_valor);
}
let t_msg: (number | string) = func_testar_if("isto é um teste");
console.log(`O resultado da execução da função é: ${t_msg}`)
Devemos perceber que a variável “t_msg” também utiliza explicitamente o narrowint. A saída, após executar o
código, é dada por:
plain-text
[LOG]: "O resultado da execução da função é: 15"
Narrowing com switch
Outra forma de fazer a verificação da tipagem é com o comando condicional “switch”. Esse comando é muito
útil para testar situações que envolvem enumeração.
Confira como utilizar o “switch”:
typescript
function func_testar_ns(par_valor: number|string): number {
switch (typeof par_valor) {
case 'number':
return par_valor;
case 'string':
return par_valor.length; //retorna o comprimento da string
default:
throw new Error('O parâmetro possui um tipo que não é suportado: ' + par_valor);
}
}
let t_msg_ns: (number | string) = func_testar_ns("isto é um teste");
console.log(`O resultado da execução da função é: ${t_msg_ns}`)
Como o parâmetro passado para a função “func_testar_ns” foi uma string, o programa retornou o
comprimento da frase, como podemos ver na saída a seguir:
plain-text
[LOG]: "O resultado da execução da função é: 15" Teste.
Atividade 2
O narrowing é uma das características do TypeScript (TS). Apesar da flexibilidade que esse recurso oferece,
ele também pode gerar dúvidas, caso não seja bem testado. Selecione a opção correta que apresenta uma
forma eficiente de fazermos a verificação de uma variáveis que usa narrowing:
A
Devemos utilizar a variável no código e deixar que o TS faça o gerenciamento dos tipos.
B
O desenvolvedor deve usar a palavra-chave “default”, pois o TS tentará usar a variável da forma padrão.
C
O desenvolvedor deve usar a palavra-chave “typeof” para estabelecer como ele deseja que a variável se
comporte dentro do programa.
D
Por meio da combinação dos comandos switch-case.
E
O desenvolvedor deve usar o símbolo “$” antes da variável para indicar que ela pode assumir tipos distintos
dentro do programa.
A alternativa D está correta.
O narrowing é um recurso bastante flexível no TypeScript. No entanto, isso faz que a responsabilidade do
desenvolvedor aumente, pois é necessário realizar testes para saber qual o comportamento esperado da
variável. Para isso, a forma mais eficiente é utilizar a combinação "switch-case".
Narrowing customizado
Ainda sobre o narrowing, há situações em que podemos realizar testes personalizados e, assim, ter mais
controle sobre a execução do programa.
Neste vídeo, apresentaremos como tratar de forma personalizada situações em que ocorre narrowing, por
meio de um exemplo concreto.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Roteiro de prática
Dado o código utilizado em nosso exemplo em vídeo, modifique-o de modo que a função possa concatenar
vetores de strings ou vetores de inteiros.
typescript
type alfanumerico = string | number | undefined;
function adicionar_concatenar(a: alfanumerico, b: alfanumerico): alfanumerico {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
if (typeof a === 'string' && typeof b === 'string') {
return a.concat(b);
}
return 'Os argumentos são inválidos. Ambos devem ser números ou strings.';
}
let t_msg_1: alfanumerico = adicionar_concatenar(10, 20);
let t_msg_2: alfanumerico = adicionar_concatenar("funcionou ", "corretamente");
let t_msg_3: alfanumerico = adicionar_concatenar(10, "t");
console.log(`Teste 1: ${t_msg_1}`)
console.log(`Teste 2: ${t_msg_2}`)
console.log(`Teste 3: ${t_msg_3}`)
Após executarmos os testes, obtemos a seguinte saída:
plain-text
[LOG]: "Teste 1: 30"
[LOG]: "Teste 2: funcionou corretamente"
[LOG]: "Teste 3: Os argumentos são inválidos. Ambos devem ser números ou strings."
Confira a seguir, o passo a passo!
Passo 1: Copia o código para o ambiente de desenvolvimento.
Passo 2: Altera o código de modo que o narrowing identifique corretamente vetores de números inteiros ou
strings.
Passo 3: Cria um conjunto de dados de teste.
Faça você mesmo!
Aplicar narrowing pode ser bastante útil, mas é necessário manter atenção para não criar programas difíceis
de entender. Por exemplo, vamos considerar o trecho de código a seguir:
plain-text
type alfanumerico = string | number | undefined;
function t(a: alfanumerico): alfanumerico {
if (typeof a === 'number') {
let x:number=0;
let i:number=1;
do{
i++;
x+=(a+i);
}while(i
Selecione a opção correta a respeito do código ao fazer a chamada como t(5):
A
Vai retornar “o resultado é: 34”.
B
Vai retornar “o resultado é: 5” .
C
Vai imprimir “string”.D
Vai imprimir “Os argumentos são inválidos”.
E
Vai retornar “o resultado é: 15”.
A alternativa B está correta.
O código do exercício aplica narrowing através do tipo definido pelo desenvolvedor que, no caso, é o
alfanumérico. Dentro da função, é feito o teste sobre o tipo do parâmetro. No exemplo dado, o parâmetro é
do tipo numérico. Apesar do laço iterativo, não é feita nenhuma alteração do valor do parâmetro e ele é
utilizado para retorno resultando, portanto, na impressão de "o resultado é: 5".
4. Classes com TypeScript
Conceitos de programação orientada a objetos
O TypeScript oferece suporte para a programação orientada a objetos. Isso é uma grande vantagem no
desenvolvimento de sistemas, pois temos recursos como encapsulamento, herança e polimorfismo, o que nos
permite escrever códigos mais organizados e eficientes.
Neste vídeo, apresentaremos o desenvolvimento de aplicações no TypeScript usando POO. Essa é uma das
vantagens que o TS oferece para auxiliar o desenvolvedor na solução de sistemas confiáveis e organizados.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
O que é programação orientada a objetos?
A programação orientada a objetos (POO) é um paradigma de desenvolvimento de software, que tem como
elemento central a utilização de classes (TYPESCRIPT HANDBOOK, 2022).
As classes são modelos computacionais compostos por campos de dados chamados de atributos e por
funções que são chamadas de métodos. Os métodos são responsáveis por manipular os atributos da classe.
Aqui, deve ficar claro que as classes são modelos. Mas, para trabalharmos no programa, precisamos de
instâncias dessas classes. Essas instâncias de classes são chamadas de objetos. O objeto é quem gerencia
os dados e aciona os métodos que vão manipulá-los.
Recomendação
Já faz algum tempo que a POO é o principal paradigma de desenvolvimento de software que existe.
Muitas linguagens de programação são baseadas em POO, sendo que a mais conhecida é o Java. O
TypeScript também dá suporte para esse de programação e é uma boa prática fazer uso dela, pois o
programa fica muito mais legível e fácil de manter.
Propriedades da POO
Vimos que o elemento central da POO é a utilização de classes. Outros conceitos importantes são os de
propriedades da POO. Através da aplicação delas, podemos garantir restrição de acesso, reusabilidade de
código e adaptabilidade de execução. As três principais propriedade de POO são:
Encapsulamento
Descreve como restringir o acesso a métodos e atributos em uma classe. O
TypeScript possui os seguintes tipos de restrição de acesso:
Privado: Membros desse tipo só podem ser acessados dentro da classe em que
foram definidos.
Protegido: Membros protegidos só podem ser acessados dentro da classe em
que foram definidos, mas também podem ser acessados pelas classes herdeiras
de uma superclasse.
Público: Todos os membros de uma classe no TypeScript são públicos, por
padrão. Os membros públicos podem ser acessados em qualquer lugar sem
nenhum tipo de restrição.
•
•
•
Herança
Permite herdar os métodos e atributos de outra classe.
Polimorfismo
Possibilita ter métodos com mesmos nomes, mas com comportamentos
distintos. O modo como o método vai se comportar vai depender de como
fazemos chamadas para ele.
Atividade 1
Uma das características que distingue o TypeScript do JavaScript é o suporte à programação orientada a
objetos (POO). A POO é um paradigma de programação muito importante e ganhou muita popularidade
através das linguagens de programação como C++, C# e Java. Selecione a opção correta que apresenta
algumas das vantagens de utilizar a POO no TypeScript:
A
Qualquer código no TypeScript deve ser desenvolvido com POO.
B
Suporte para utilizar arrow functions nos métodos das classes.
C
As classes aceleram o processamento de um código.
D
A POO é a técnica mais moderna de desenvolvimento de software.
E
Reutilização e flexibilidade de código.
A alternativa E está correta.
A utilização de POO no TypeScript auxilia a depuração mais fácil do código, na reutilização dele através da
propriedade de herança, aumenta a flexibilidade por meio do uso do polimorfismo e é mais eficaz na
resolução de problemas devido à representação que uma classe oferece por seus atributos e métodos.
As propriedades de encapsulamento e herança
Quando desenvolvemos um sistema, é muito importante que possamos garantir um comportamento estável
dele. Nesse sentido, a propriedade de encasulamento permite oferecer essa robustez e controlar a
visibilidade dos métodos da classe.
Neste vídeo, apresentaremos como desenvolver uma aplicação com a propriedade de encapsulamento.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Encapsulamento
Para aplicar o encapsulamento, o TypeScript fornece três tipos de modificadores, que são private, protected
e public que correspondem, respectivamente, aos tipos de acesso privado, protegido e público, como vimos.:
Observe um exemplo prático desses modificadores de acesso:
typescript
class Pessoa {
private nome: string = ‘’; // default
protected ender: string = ‘’;
constructor(nome: string, ender: string = ‘’) {
this.set_nome(nome);
this.set_ender(ender);
}
private set_nome = (nome: string) => {
this.nome = nome;
}
private set_ender = (ender: string) => {
this.ender = ender;
}
public get_nome = ():string => {
return this.nome;
}
public get_ender = ():string => {
return this.ender;
}
}
const pessoa = new Pessoa(‘Teste’, ‘rua de pedra’);
console.log(`Dados da pessoa: nome = ${pessoa.get_nome()}, endereço = $
{pessoa.get_ender()} `)
No final do código, definimos um objeto “pessoa” como uma classe “Pessoa”. Apesar de os nomes serem
iguais, o TypeScript os diferencia, pois é sensível à utilização de letras maiúsculas e minúsculas. Esse código
tem vários aspectos interessantes, entre as quais destacamos as seguintes:
Utilização dos modificadores private, protected e public.
Aplicação de Arrow Functions para definir os métodos da classe.
•
•
Passagem de valores para os atributos da classe através do construtor. Esse método é responsável por
estabelecer o comportamento inicial dos objetos.
Veja a saída resultante da execução do programa:
plain-text
[LOG]: "Dados da pessoa: nome = Teste, endereço = rua de pedra
Herança
Agora, vamos apresentar um exemplo prático da propriedade de herança. Criamos duas classes: PessoaFisica
e PessoaJuridica. Ambas herdam as características da classe Pessoa que apresentamos no exemplo anterior.
Para indicar a herança, o TypeScript utiliza a plavra-chave “extends”.
Confira o exemplo de herança:
•
typescript
class PessoaFisica extends Pessoa {
private cpf: string = ''; // default
constructor(nome: string, ender: string = '', cpf: string) {
super(nome,ender);
this.set_cpf(cpf);
}
private set_cpf = (cpf: string) => {
this.cpf = cpf;
}
public get_cpf = ():string => {
return this.cpf;
}
public get_dados = ():void => {
console.log(`Dados da pessoa física: nome = ${this.get_nome()},
endereço = ${this.get_ender()}, cpf = ${this.get_cpf()}`)
}
}
class PessoaJuridica extends Pessoa {
private cnpj: string = ''; // default
constructor(nome: string, ender: string = '', cnpj: string) {
super(nome, ender);
this.set_cnpj(cnpj);
}
private set_cnpj = (cnpj: string) => {
this.cnpj = cnpj;
}
public get_cnpj = ():string => {
return this.cnpj;
}
public get_dados = ():void => {
console.log(`Dados da pessoa jurídica: nome = ${this.get_nome()},
endereço = ${this.get_ender()}, cpf = ${this.get_cnpj()}`)
}
}
const pessoa_fisica = new PessoaFisica('Isaac Newton', 'rua das maçãs', '100001811-82')
const pessoa_juridica = new PessoaJuridica('TypeScript S.A.', 'rua dos tipos',
'921.0001-07')
pessoa_fisica.get_dados();
pessoa_juridica.get_dados();
Os principais destaques desse exemplo são:
A utilização da palavra-chave “extends” para fazer a herança das classes.
A implementação do método “get_dados” tanto na classe “PessoaFisica”, como na classe “PessoaJuridica” com
a manipulação de diferentes dados.
Veja as saídas da execução do código:
•
•
plain-text
[LOG]: "Dados da pessoa: nome = Teste, endereço = rua de pedra"
[LOG]: "Dados da pessoa: nome = Teste, endereço = rua de pedra"
[LOG]: "Dados da pessoa física: nome = Isaac Newton, endereço = rua das maçãs, cpf =
100001811-82"
[LOG]: "Dados da pessoa jurídica: nome = TypeScript S.A., endereço = rua dos tipos, cpf =
921.0001-07"
Atividade 2
Uma das propriedades da programação orientada a objetos é a herança. O TypeScript (TS) dá suporte a essa
propriedade e é uma grande vantagem utilizá-la. Selecione a opção correta a respeito das vantagens de
utilizar a propriedade herança no TS:
A
Como a programação orientada a objetos é uma técnica recente e bastante avançada, a herança é mais uma
das propriedades que devemos usar para extrair o máximo dessa forma de programação.
B
O TS é uma linguagem orientada a objetos que nos obriga a utilizar os melhores padrões de desenvolvimento
como no caso da propriedade herança.
C
A herança garante que as classes filhas desenvolvam os métodos da classe mãe fazendo com que o código
fique padronizado.
D
Além de reaproveitar códigos, podemos usar a herança para estender comportamentos.
E
A maior vantagem de aplicar a propriedade herança no TS é devido à documentação que ela nos obriga a
fazer, para facilitar a manutenção do código posteriormente.
A alternativa D está correta.
A herança é uma propriedade da programação orientada a objetos (POO) que nos permite transferir
atributos e métodos para classes filhas. Como a linguagem TS utiliza a POO, podemos fazer uso desse
recurso para padronizar nossos códigos e reutilizá-los no desenvolvimento de diferentes sistemas com
características semelhantes.
A propriedade de polimorfismo
O polimorfismo é uma das propriedades mais complexas da POO. No entanto, há situações nas quais ela se
encaixa muito bem. É importante que o desenvolvedor conheça essa propriedade, pois, há casos em que ela
torna a implementação muito mais simples e de fácil manutenção.
Neste vídeo, apresentaremos como desenvolver uma aplicação com a propriedade de polimorfismo.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Polimorfismo
A última propriedade que vamos estudar é o polimorfismo. No exemplo, a classe “LinguaPortuguesa” herda as
características da classe “LinguaLatina”. Nas duas classes, implementamos o método “exibir_informacao()”,
mas o resultado gerado pela execução do programa é diferente, devido ao escopo em o método é
implementado.
Veja o exemplo completo:
typescript
class LinguaLatina {
public exibir_informacao():void {
console.log("Esta classe contém informações sobre a língua latina");
}
}
class LinguaPortuguesa extends LinguaLatina{
public exibir_informacao():void {
console.log("Esta classe contém informações sobre a língua portuguesa");
}
}
const obj1 = new LinguaLatina()
const obj2 = new LinguaPortuguesa()
obj1.exibir_informacao()
obj2.exibir_informacao()
Cuja saída é dada por:
plain-text
[LOG]: "Esta classe contém informações sobre a língua latina"
[LOG]: "Esta classe contém informações sobre a língua portuguesa"
Na saída, podemos perceber claramente que os métodos executados foram diferentes.
Atividade 3
O polimorfismo é uma das propriedades da programação orientada a objetos (POO). O uso dela não é natural
como no caso das propriedades de encapsulamento e herança, mas há situações em que ela é muito
vantajosa. O TypeScript (TS), como era de se esperar, também dá suporte a essa propriedade. Selecione a
opção correta a respeito das vantagens de utilizar a propriedade de polimorfismo no TS:
A
O polimorfismo garante que uma classe mãe vai padronizar o comportamento de todas as classes herdeiras.
B
No TS, o polimorfismo aumenta o desempenho com o qual um método será processado que, de fato, é uma
grande vantagem em aplicações web.
C
O polimorfismo elimina a necessidade de o programador fazer chamadas a diferentes métodos, necessitando
apenas determinar a classe e os parâmetros.
D
O polimorfismo estabelece a visibilidade dos atributos de uma classe fazendo com que apenas métodos
públicos tenham acesso aos dados dos atributos.
E
A grande vantagem de aplicar a propriedade de polimorfismo no TS é por causa da flexibilidade de
comportamento que ela pode ter para diferentes contextos utilizando exatamente o mesmo nome do método.
A alternativa E está correta.
O polimorfismo é uma das propriedades da POO que deve ser usado em situações bastante específicas,
pois o uso inadequado pode criar confusão. Por outro lado, há situações em que ele é bastante adequado.
Em especial, quando queremos tratar situações semelhantes como, por exemplo, renderização de objetos,
mas os parâmetros, obviamente, são diferentes, apesar de o comportamento esperado para o método ser
semelhante.
Classe genérica
Um dos papéis de responsabilidade mais importantes no desenvolvimento de um sistema é o do arquiteto de
softwares. Isso porque é ele quem deve estabelecer as diretrizes que os desenvolvedores devem seguir para
implementar as funcionalidades de forma padronizada. Um importante recurso para alcançar esse objetivo é
o uso das classes genéricas que são suportadas pelo TypeScript.
Neste vídeo, apresentaremos o desenvolvimento de uma aplicação com a propriedade de polimorfismos.
Conteúdo interativo
Acesse a versão digital para assistir ao vídeo.
Aspectos conceituais da classe genérica
O TypeScript suporta a utilização de classes genéricas. Classes genéricas são estruturas lógicas que
generalizam comportamentos sem ficar vinculadas a um tipo específico de dado. São úteis, especialmente,
para a construção de componentes. Para utilizá-las no código, é necessário especificar