👋 Fala Dev,
A seguir teremos anotações sobre typescript, o curso irá abordar os principais conceitos e projetos na prática.
Table of Contents
O que é o Typescript?
- Typescript é um superset para a linguagem JavaScript
- Ou seja, adiciona funções ao JavaScript, como a declaração de tipos de variável.
- Pode ser utilizado no desenvolvimento de projetos com NodeJS e express para criação de APIS, e bibliotecas como React.
- Precisa ser compilado pra JavaScript, pois não executamos TS;
- Desenvolvido e mantido pela Microsoft
Exemplo
let x: number = 10;
console.log("antes", x);
x = 16;
console.log("depois", x);
Inferencia X Annotation
Ao trabalhar com projetos em typescript, será necessário estar familiarizado com qual caminho de tipagem seu código irá seguir.
//Inferencia X Annotation
let z = 16;
// z="teste" -- erro
let y: number = 16;
Ou seja, podemos perceber que na inferência o Typescript entende a qual tipo a variável está sendo atribuída.
Porém cabe ressaltar que nem sempre a inferência vai funcionar, dado os contextos de cada situação, sendo necessário a recorrência da tipagem conforme segundo exemplo.
Analisando Tipagem Básica
let firstName: string = "Marlon";
let age: number = 25;
const isAdmin: boolean = true;
console.log(typeof firstName);
age = 26;
console.log(age);
String !== string
- Em javascript nós temos os objetos que são em letra maiúscula, e as variáveis em letras minúsculas, porém em Typescript sempre iremos trabalhar com as letras minúsculas
Lembrando que o console do teu tipo deve ser o tipo que será utilizado para declarar o tipo da variável.
Analisando a Tipagem de Objetos
Array
Para trabalhar com listas e arrays, devemos utilizar a seguinte sintaxe:
const myNumbers: number[] = [1, 2, 3];
//declaramos o array como sendo um array de numbers
//sendo assim já podemos utilizar as propriedades do array como:
console.log(myNumbers);
console.log(typeof myNumbers);
console.log(myNumbers.length);
myNumbers.push(4);
console.log(myNumbers);
Tuple
No python, as tuplas são arrays cujos valores inseridos não podem ser modficados, no typescript, as tuplas terão suas tipagens declaradas dentro do array, como no exemplo abaixo:
let myTuple: [number, string, string[]];
myTuple = [5, "teste", ["a", "b"]];
// myTuple = [true, false, true] -- erro
Object Literals
Ao declarar objetos, uma chaves irá receber a tipagem dos dados, enquanto que a segunda chaves irá receber os dados de informação, por exemplo:
//object literals -> {prop: value}
const user: {
name: string;
age: number;
} = {
name: "Marlon",
age: 25,
};
console.log(user);
console.log(user.name);
// user.job = "programador" -- erro
Analisando Tipagem Múltipla
Any
O any foi feito pra aceitar qualquer tipo, indo contra a "filosofia" do typescript, mas também para definirmos uma variável que pode receber qualquer tipo de valor.
let a: any = 0;
a = "teste";
a = true;
a = [];
Lembrando que o any não deve ser utilizado em qualquer circunstância, mas sim dentro de um contexto específico onde não se pode prever o tipo do valor retornado ou declarado. Utilizá-lo fora desse contexto pode ser considerado uma má prática.
Union Type
Uma das formas de se unir tipos para criar um outro tipo mais complexo, pode ser chamado de union type. Essa seria uma maneira mais ==typescript== de se resolver os problemas de utilização de any
fora de contexto, ou seja, não sabemos se os dados serão retornados em string
ou number
, aí ao invés de se utilizar o any
podemos aderir ao union type, como no caso do id que dependendo do formato do projeto pode ser retornado como string
ou number
.
let id: string | number = "1";
id = 200;
// id = true -- erro
Type Alias
Uma maneira eficiente de se criar código limpo e reutilizável é usando o type alias, como uma solução para o caso de decidir adicionar mais um tipo a variável ID do exemplo anterior, não sendo necessário deixar o código extenso, podemos adicionar um alias e reduzir a tipagem:
type myIdType = number | string;
const userId: myIdType = "1";
const productId: myIdType = 200;
const shirId: myIdType = 123;
// id = true -- erro
Enum
Um tipo de dado que enumera uma coleção para trabalharmos dados mais complexos de uma maneira mais simples, por exemplo:
// exemplo: tamanho de roupas (size: Médio, size: Pequeno)
enum Size {
P = "pequeno",
M = "Médio",
G = "Grande",
}
const camisa = {
name: "Camisa Gola V",
size: Size.P,
};
console.log(camisa);
Analisando Tipagem Literal
Podemos aplicar valores literais para um tipo, sendo assim impossível que esse valor seja alterado posteriormente.
let teste: "algumvalor";
// teste = "outrovalor" -- erro
teste = "algumvalor";
Geralmente para poder resetar o valor aplicado a sua variável devemos usar o union type para declarar que a variável pode ser null, por exemplo
let teste2: "algumvalor" | null;
teste2 = "algumvalor";
teste2 = null;
Analisando Funções
Função Básica
Para se criar uma função no typescript, devemos usar a mesma semântica do javascript, porém todos os argumentos passados para a função devem ser tipados:
function sum(a: number, b: number) {
return a + b;
}
console.log(sum(12, 13));
// console.log(sum("12", true)); -- erro
Tipagem do Retorno
Além de informar o tipo do parâmetro que estamos declarando, caso uma função tenha retorno, podemos declarar como no primeiro exemplo, e quando a função não possui retorno utilizamos a declaração do void para fazer a tipagem do retorno da função.
// Estamos informando que o retorno da função
// deve ser uma string
function sayHelloTo(name: string): string {
return `Hello ${name}`;
}
console.log(sayHelloTo("Marlon"));
// Quando a função não retornar nada como no
// exemplo abaixo podemos usar o void
function logger(msg: string): void {
console.log(msg);
}
logger("Hello World");
Parâmetros opcionais
Caso algum dos parâmetros da função sejam opcionais como no exemplo abaixo, podemos utilizar o ==?== e fazer as devidas tratativas de condicionais.
function greeting(name: string, greet?: string): void {
console.log(`Olá, ${greet} ${name}`);
if (greet) {
console.log(`Olá, ${greet} ${name}`);
} else {
console.log(`Olá, ${name}`);
}
}
greeting("Marlon");
greeting("Marlon", "Sir");
Ao usar o "?", colocamos o greet como opcional, não sendo obrigatório o parâmetro. Porém perceba que há um erro de lógica acima, onde o log do greet virá como undefined, o typescript não aponta esse erro pois colocamos o parâmetro como opcional, sendo responsabilidade do desenvolvedor tratar essa obrigatoriedade, como no exemplo acima.
Interfaces
As interfaces são um recurso do typescript que veio para o javascript, que padronizam algo para que possamos reutilizar como um tipo.
interface MathFunctionsParams {
n1: number;
n2: number;
}
// perceba que são dois parâmetros para uma função matemática, porém usando interface(objeto) e enum
function sumNumbers(nums: MathFunctionsParams) {
return nums.n1 + nums.n2;
}
const result: number = sumNumbers({ n1: 1, n2: 2 });
console.log(result);
// utilizando de outras formas
const someNumbers: MathFunctionsParams = {
n1: 5,
n2: 10,
};
function multiplyNumbers(nums: MathFunctionsParams) {
return nums.n1 * nums.n2;
}
const result2: number = multiplyNumbers(someNumbers);
console.log(result2);
Narrowing
Quando não sabemos qual tipo exato será o parâmetro de uma função, mas precisamos fazer uma tratativa com esses resultados, podemos usar o narrowing do typeof para tratar as condicionais:
function doSomething(info: number | boolean) {
if (typeof info === "number") {
console.log(`O número é ${info}`);
return;
}
console.log(`Não foi passado nenhum número`);
}
doSomething(5)
doSomething(true)
Ao verificar o typeof de um parâmetro, estamos usando um narrowing de typeof para garantir que o retorno será de acordo com o parâmetro passado.
Generics
Um outro recurso do typescript é o generics, que para se evitar um any, pode ser aplicado em diferentes situações que possuem a necessidade de se declarar um tipo genérico, que pode receber mais de um tipo de valor não esperado, como uma função que mostra os itens de um array, porém não sabemos se os itens virão como number, string, ao invés do any podemos utilizar o generics para declarar um tipo genérico seguindo a seguinte linha de desenvolvimento
function showArrayItems<T>(arr: T[]) {
arr.forEach((item) => {
console.log(item);
});
}
const a1 = [1, 2, 3];
const a2 = ["1", "2", "3"];
showArrayItems(a1);
showArrayItems(a2);
Usamos a tag <> após o nome da função para remeter a algo genérico, como por exemplo T e U (que são mais utilizados no typescript). No caso acima utilizamos a tag T referenciando dentro do parâmetro para exemplificar que esperamos receber qualquer tipo de dado nesse array, porém sendo mais especificado que um simples any.
Classes
Class é um método de orientação a objeto utilizado para definir novas classes como no exemplo abaixo:
class User {
name;
role;
isApproved;
constructor(name: string, role: string, isApproved: boolean) {
this.name = name;
this.role = role;
this.isApproved = isApproved;
}
}
const marlon = new User("Marlon", "admin", true);
console.log(marlon);
Na utilização de classes, precisamos usar um constructor pois o typescript solicita numa class a tipagem dos dados e um inicializador, portanto sendo mais sucinto declarar os tipos num constructor e utilizar a tipagem por inferência, ou seja, declarar no constructor os tipos e atribuir aos valores do objeto.
Podemos também utilizar os constructor para criar métodos, como por exemplo:
class User {
name;
role;
isApproved;
constructor(name: string, role: string, isApproved: boolean) {
this.name = name;
this.role = role;
this.isApproved = isApproved;
}
showUserName() {
console.log(`O nome do usuário é ${this.name}`);
}
}
const marlon = new User("Marlon", "admin", true);
marlon.showUserName();
Um outro exemplo utilizando parâmetros:
class User {
name;
role;
isApproved;
constructor(name: string, role: string, isApproved: boolean) {
this.name = name;
this.role = role;
this.isApproved = isApproved;
}
showUserRole(canShow: boolean) {
if (canShow) {
console.log(`O role do usuário é ${this.role}`);
return;
}
console.log(`informação restrita!`);
}
}
const marlon = new User("Marlon", "admin", true);
console.log(marlon);
marlon.showUserRole(true);
marlon.showUserRole(false);
Interfaces em classes
Interfaces é o core da orientação a objetos, geralmente sendo utilizada para ditar como uma classe irá se comportar. Sendo muito útil em projetos onde há classes que são muito parecidas, ou seja, tendo um padrão entre elas. Um exemplo de uma interface de veículos:
interface IVehicle {
brand: string;
showBrand(): void;
}
class Car implements IVehicle {
brand;
wheels;
constructor(brand: string, wheels: number) {
this.brand = brand;
this.wheels = wheels;
}
showBrand(): void {
console.log(`A marca do carro é ${this.brand}`);
}
}
const mustang = new Car("Ford", 4);
mustang.showBrand();
Para criar interfaces, utiliza-se a letra "I" no início do nome para especificar que será uma interface. No exemplo acima, a interface "IVehicle" é utilizada na class "Car" através do comando "implements".
Herança
Uma class também pode herdar outra class, como por exemplo, criando uma nova class Super Car que herda os tipos da class no exemplo anterior Car:
class SuperCar extends Car {
engine;
constructor(brand: string, wheels: number, engine: number) {
super(brand, wheels);
this.engine = engine;
}
}
// criando uma nova class supercar com herança
const a4 = new SuperCar("Audi", 4, 2.0);
console.log(a4);
a4.showBrand();
No exemplo acima utilizamos uma nova class que possui sua herança da class Car, porém nessa nova class adicionamos a nova chave "engine". Para se utilizar o constructor dentro da class herdada, devemos passar os tipos que declaramos no constructor "pai" e o novo declarado no constructor filho, e para atribuir os valores, utilizamos o "super" para extrair esses valores da class "pai".
Decorators
Os decorators são um recurso do typescript muito utilizados para validação de dados, para construir um evento observável em alguma class ou função. Um recurso complexo para quem é iniciante no typescript. Porém caso deseje utilizar, lembre-se de habilitar o mesmo dentro do seu arquivo de configuração, através da chave experimentalDecorators
.
class Person {
name;
constructor(name: string) {
this.name = name;
}
}
Temos a class Person que recebe a variável name quando o usuário é criado, porém se quiser adicionar um id e uma data de criação para esse usuário, podemos utilizar um constructor, uma vez que não é o usuário que preenche essas informações, ambas devem ser geradas pelo sistema.
Constructor são funções que retornam outras funções que contenham as informações que queremos alterar na class base.
function BaseParams() {
return function <T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
id = Math.random();
createdAt = new Date();
};
};
}
//Chamando o constructor
@BaseParams()
class Person {
name;
constructor(name: string) {
this.name = name;
}
}
const newUserMarlon = new Person("Marlon");
console.log(newUserMarlon);
A função baseParams basicamente cria os parâmetros base para a criação de qualquer outra class, nesse caso contendo um id e uma data de criação.
Para trabalhar com construtores, devemos esperar qualquer tipo de argumento, pois como serão parâmetros base para as classes, teremos provavelmente classes diferentes umas das outras, portanto adotar uma abordagem mais genérica, tentando sempre evitar o any. Para isso utilizaremos a tag genérica.
Para utilizar um constructor devemos usar o "@" para exemplificar que estamos utilizando um constructor dentro do código.
Configurando o Projeto
Verificar se o typescript está instalado na máquina:
npx tsc -v
Ou usando yarn:
yarn tsc -v
Caso não tenha o typescript instalado na sua máquina, verifique a documentação para poder instalar de acordo com seu gerenciador de pacotes preferido.
Assim que tiver o arquivo instalado na máquina, pode prosseguir com o seguinte comando para iniciar um arquivo de configuração:
Certifique-se de já estar dentro do seu diretório
npx tsc --init
Arquivo de configuração criado, pode-se alterar esse arquivo tsconfig.json
da seguinte maneira:
rootDir
- Diretório root, deve ser alterado para onde ficará armazenado o index.ts da sua aplicação (No caso do projeto a pasta src);
outDir
- Diretório de saída, deve ser apontado o diretório que será compilado o arquivo javascript, nesse caso dentro da pasta dist na pasta js
Para validar, crie seu "Hello World" no arquivo
index.ts
e para compilar rode no seu terminal o comandonpx tsc
, e certifique-se se a leitura do arquivo de entrada e saída estão de acordo.
target
- O target define a linguagem javascript que será compilada, portanto certifique-se de utilizar a versão que mais se adapta ao seu projeto.
Ao final, sua estrutura deve ficar parecido com algo tipo isso:
├── dist (or build)
│ ├── js
│ │ ├── index.js
│ ├── index.html
├── src
│ ├── index.ts
└── tsconfig.json
Compilando o Projeto
Para que o arquivo index.js seja observado pelo typescript para que qualquer alteração seja alterado novamente, podemos usar o comando:
npx tsc -w
Se você utiliza o VScode como IDE, pode-se usar a extensão live-server para abrir um servidor para servir sua aplicação estática, e tendo acesso ao console poderá ver o javascript que está sendo gerado pelo typescript.
Top comments (0)