Junior Alves
Senior Developer
Foto: Unsplash
19 de setembro de 2020 • 8 minutos de leitura
Aprendendo TypeScript - Parte 1
Iniciando os estudos com TypeScript
- Instalação
- Tipos primitivos
- Type Inference
- Type Aliasses
- Classes
- Modifiers (public, private, readonly, protected)
- Getters e Setters
- Abstract
- Interfaces
- Propriedades opcionais
- Extender interfaces
- Implements
- Conclusão
Instalação
Primeiramente, precisamos ter o Node.js em instalado em nossa máquina.
Após instalar o Node.js, podemos prosseguir com a instalação do TypeScript, basta rodar o comando:
npm install -g typescript
Agora, para criamos um arquivo de configuração do TypeScript, podemos executar:
tsc --init
Na raíz do projeto, será criado um arquivo tsconfig.json
, como esse:
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist", // Pasta para onde será compilado
"baseUrl": "./",
"incremental": true
}
}
Nota
O arquivo terá muitas outras configurações comentadas, mas as mais importante para esse momento inicial, são essas acima.
Tipos primitivos
boolean (true / false)
let isOpen: boolean;
isOpen = true;
String
// 'foo', "foo", `foo`
let message: string;
message = `foo ${isOpen}`;
Number
// (int, float, hex, binary)
let total: number;
total = 0xff0;
Array
// (type[])
// Primeira notação
let items: string[];
items = ['foo', 'bar'];
// Segunda notação
let values: Array<number>; // Generic
values = [1, 2, 3];
Tuple
// Array, onde ja sei qual os tipos e qual o tamanho do Array
let title: [number, string];
title = [1, 'foo']; // correto
title = [1, 'foo', true]; // errado
Enum
// Conjunto chave valor, facilitando a identificação
enum Colors {
white = '#fff';
black = "#000";
}
Any
// Qualquer coisa TERROR DO TS, NÃO UTILIZAR!!
let coisa: any; // ou let coisa;
coisa = [1];
coisa = 'foo';
Void
// Vazio, nao retorna nada. Usado para tipar funções onde não é retornado nada!
function logger(): void {
console.log('foo');
}
Null / undefined
Never
// Um erro não retorna nada, nunca retorna nada, sempre vai cair na excessão
function error(): never {
thow new Error("error");
}
Object
let cart: object;
cart = {
key: 'fi'
};
Type Inference
// O TS faz um Type Inference para string, no caso!
let message = 'mensagem'; // Define que message é do tipo string
message = 1; // Erro!
No TypeScript não precisamos tipar tudo, apenas o que for necessário!
Type Aliasses
function logDetails(uid: number, item: string) {
console.log(`A product with ${uid} has a title as ${item}.`);
}
logDetails(123, "sapato"); // Certo!
logDetails("123", "sapato"); // Errado!
// Corrigindo
function logDetails(uid: number | string, item: string) {...}
logDetails("123", "sapato"); // Agora está correto
Mas o Type Aliasses é muito mais poderoso que isso...
// Type Alias
type Uid = number | string;
// Varios funções, onde os parâmetros são do tipo Uid, que eu criei!
function logDetails(uid: Uid, item: string){...}
function logInfo(uid: Uid, user_name: string){...}
Outro exemplo:
type Platform = 'Windows' | 'Linux' | 'MacOS';
function renderPlatform(platform: Platform) {
return platform;
}
renderPlatform('ios'); // Retorna erro!
renderPlatform('Windows'); // Retorna Windows
type AccountInfo = {
id: number;
name: string;
email?: string; // O "?" significa que esse atributo é opcional (string | undefined)
}
const account: AccountInfo = {
id: 123,
name: "Junior"
email: "junior@email.com"
}
type CharInfo = {
nickname: string;
level: number;
}
type PlayerInfo = AccountInfo & CharInfo; // Junta os dois tipos (Intersection)
// Não é necessário passar na mesma ordem!
const player: PlayerInfo = {
id: 123,
name: "Junior"
email: "junior@email.com",
nickname: "junior996";
level: 10;
}
Classes
class UserAccount {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
logDetails(): void {
console.log(`The player ${this.name} is ${this.age} years old`);
}
}
const user = new UserAccount("Junior", 23); // Cria uma instância de UserAccount
user.logDetails(); // Executa o método da classe
// Herança
class CharAccount extends UserAccount {
nickname: string;
level: number;
constructor(name: string, age: number, nickname: string, level: number) {
// pega as propriedades superior, da classe que estamos extendendo
super(name, age) {
this.nickname = nickname;
this.level = level;
}
}
}
const newUser = new UserAccount("Marcos", 32, "marcos123", 82);
newUser.logDetails();
Para rodar:
tsc --watch # irá compilar os arquivos .ts
yarn add nodemon -D # instalar o Nodemon nodemon dist/nome_arquivo.js # para executar
Modifiers
Public
É implícito, quando não passamos nenhum modifier, ele é atribuído por padrão.
Private
Permite acessar e modificar as propriedades dentro da classe.
Readonly
Permite, fora da classe, apenas acessar, não alterar.
Protected
Semelhante ao private, porém, permite ser acessada dentro das subclasses também, já o private não, apenas dentro da própria classe.
class CharAccount extends UserAccount {
private nickname: string; // nickname só pode ser acessado dentro dessa classe!
readonly level: number; // readonly permite apenas ler, não editar a propriedade!
constructor(name: string, age: number, nickname: string, level: number) {
super(name, age) {
this.nickname = nickname;
this.level = level;
}
}
}
const newUser = new UserAccount("Marcos", 32, "marcos123", 82);
newUser.nickname; // Error!
newUser.level; // Funciona!
newUser.level = 99 // Error! Só pode ser lida, não alterada
Getters & Setters
class UserAccount {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
logDetails(): void {
console.log(`The player ${this.name} is ${this.age} years old`);
}
get getName() {
console.log('---GET---');
return this.name;
}
set setName(name: string) {
this.name = name;
}
}
const user = new UserAccount('Junior', 23); // Cria uma instância de UserAccount
user.getName; // Acessa o getName, como se fosse uma propriedade
user.setName = 'Jorge';
Abstract
Classes que são apenas modelos para outras classes, não podemos criar instâncias a partir delas.
Significa que, eu não consigo criar um objeto a partir dessa classe. Eu só consigo estender essa classe.
abstract class UserAccount {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const user = new UserAccount('Marcos', 32, 'marcos123', 82); // Error!
Interfaces
Um conjunto de dados para descrever a estrutura de um objeto. Exclusivamente para objetos.
interface Game {
title: string;
description: string;
genre: string;
platform: string[];
getSimilars: (title: string) => void; // Assinatura dos métodos
}
const theLastOfUs: Game = {
title: 'The Last of Us',
description: 'The best game in the world',
genre: 'Action',
platform: ['PS3', 'PS4'],
getSimilars: (title: string) => {
console.log(`Similar games to ${title}: Metro, Uncharted`);
}
};
theLastOfUs.title; // "The Last of Us"
Os modifiers funcionam para as interfaces (public, private, readonly, protected)
interface Game { title: string; readonly description: string; genre: string; platform: string[]; getSimilars: (title: string) => void; }
Propriedades opcionais
interface Game {
title: string;
description: string;
genre: string;
platform?: string[]; // platform é opcional (?), posso passar ou não
getSimilars: (title: string) => void;
}
Estender interfaces
Semelhante as classes, as interfaces também podem estender de outras interfaces.
interface Game {
title: string;
description: string;
genre: string;
platform: string[];
getSimilars: (title: string) => void;
}
const theLastOfUs: Game = {
title: "The Last of Us",
description: "The best game in the world",
genre: "Action",
platform: ["PS3", "PS4"],
getSimilars: (title: string) => {
console.log(`Similar games to ${title}: Metro, Uncharted`);
}
}
interface DLC extends Game {
originalGame: Game; // Objeto com todos as propriedades da interface Game
newContent: string[];
}
const leftBehind: DLC = {
title: "The Last of Us - Left Behind",
description: "You play as Ellie",
genre: "Action",
platform: ["PS3", "PS4"],
originalGame: theLastOfUs, // Objeto inteiro, declarado acima!
newContent: ["3 hours story", "new caracters"]
getSimilars: (title: string) => {
console.log(`Similar games to ${title}: Metro, Uncharted`);
}
}
Implements
Posso extender uma classe de uma interface.
Como? Com o implements
.
interface Game {
title: string;
description: string;
genre: string;
platform?: string[]; // Propriedade opcional (?)
getSimilars?: (title: string) => void; // Propriedade opcional (?)
}
class CreateGame implements Game {
title: string;
description: string;
genre: string;
constructor(t: string, d: string, g: string) {
this.title = t;
this.description = d;
this.genre = g;
}
}
Mini curso sobre TypeScript
Conclusão
Nesse post, vimos um resumo de algumas funcionalidades do TypeScript. Nos próximos posts, iremos aprender mais afundo cada uma delas, além de outras funcionalidades. Grande abraço e até a próxima!
Curtiu? Compartilhe esse post: