TypeScript

Sintaxe TypeScript
Voltar
Conteúdo disponível

Conceito:

Linguagem da Microsoft, transpilada em JavaScript, atribuída de conceitos OOP como classes, módulos, interfaces, genéricos e (opcional) tipagem estática para JavaScript. Arquivos TypeScript possuem final '.ts'. Todo código JavaScript é TypeScript válido, podendo ser adicionado a qualquer projeto. Pode ser testado no playground online. Para transpirar arquivos TS para JS, utiliza-se comando "tsc arquivo.ts".


Instalação:


npm install -g typescript // Pré-requisito Node.js
tsc -v

Tipos de dados:


console.log("Olá!"); // Imprimir no console
var isDone: boolean = false; // Booleano true ou false
var lines: number = 42; // Números inteiros ou decimais
var name: string = "Anders"; // String com aspas duplas ou simples

var notSure: any = 4; // Qualquer tipo
notSure = "maybe a string instead";
notSure = false;

var list: number[] = [1, 2, 3]; // Matriz
var list: Array<number> = [1, 2, 3]; // Matriz genérica

// Percorrer valores da matriz
for (var i = 0; i < list.length; i++) {
    console.log(list[i]);
}
for (var i in list) {
    console.log(list[i]);
}
for (var i of list) {
    console.log(i);
}

var x: [string, number]; // Tupla
x = ["hello", 10]; // OK
x = [10, "hello"]; // Erro

enum Color {Red, Green, Blue}; // Enumeração
var c: Color = Color.Green; // 1
var colorName: string = Color[2]; // Blue

var notSure: unknown = 4; // Tipo desconhecido
var u: undefined = undefined; // Indefinido
var n: null = null; // Nulo

function bigHorribleAlert(): void { // Vazio (sem retorno)
    alert("I'm a little annoying box!");
}

Funções:


function soma(x: number, y: number): number {
    return x + y;
}
console.log(soma(1, 2)); // 3

// Função com parâmetros opcionais
function buildName(firstName: string, lastName?: string): string {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}
console.log(buildName("John")); // John
console.log(buildName("John", "Doe")); // John Doe

// Função anônima
var f1 = function (i: number): number { return i * i; }
console.log(f1(3)); // 9

// Tipo de retorno inferido
var f2 = function (i: number) { return i * i; }
console.log(f2(4)); // 16

var f3 = (i: number): number => { return i * i; }
console.log(f3(5)); // 25

// Tipo de retorno inferido
var f4 = (i: number) => { return i * i; }
console.log(f4(6)); // 36

// Tipo de retorno inferido, one-liner significa nenhuma palavra-chave retorno necessário
var f5 = (i: number) => i * i;
console.log(f5(2)); // 4

Interfaces:


interface Pessoa {
    nome: string;
    idade: number;
    sexo?: string; // Opcional
    [propName: string]: any; // Propriedades dinâmicas
}

function printPessoa(pessoa: Pessoa) {
    console.log(pessoa.nome);
    console.log(pessoa.idade);
    console.log(pessoa.sexo);
}

var p1 = {nome: "João", idade: 25};
printPessoa(p1);

// Interfaces como tipo de função
interface SearchFunc {
    (source: string, subString: string): boolean;
}

var mySearch: SearchFunc;
mySearch = function(src: string, sub: string) {
    return src.search(sub) != -1;
}
console.log(mySearch("abc", "a")); // true
console.log(mySearch("abc", "d")); // false

Objetos:


// Implementação de interface
interface Usuario {
    id: number;
    nome: string;
    email: string;
}

// Objeto que implementa interface Usuario
const user: Usuario = {
    id: 1,
    nome: "Maria",
    email: "maria@email.com"
};

console.log("Usuário:");
console.log(`ID: ${user.id}`);
console.log(`Nome: ${user.nome}`);
console.log(`Email: ${user.email}`);

// Objeto com propriedades dinâmicas
const obj: { [key: string]: string } = {
    nome: "João",
    idade: "25"
};

// Exibir dados do objeto com propriedades dinâmicas
console.log("\nObjeto com propriedades dinâmicas:");
for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(`${key}: ${obj[key]}`);
    }
}

// Objeto construído através de classe
class Pessoa {
    nome: string;
    idade: number;
    constructor(nome: string, idade: number) {
        this.nome = nome;
        this.idade = idade;
    }
    printPessoa() {
        console.log(this.nome);
        console.log(this.idade);
    }
}

var p1 = new Pessoa("João", 25);
p1.printPessoa();
var p: Pessoa = {nome: "João", idade: 25}; // Objeto que implementa interface Pessoa

var p: Person = { name: "Bobby", move: () => {} };
var validPerson: Person = { name: "Bobby", age: 42, move: () => {} }; // Propriedade opcional
var invalidPerson: Person = { name: "Bobby", age: true }; // Não é Person porque age não é número

Classes:


class Animal {
    nome: string;

    constructor(nome: string, public idade: number = 0) {
        this.nome = nome;
    }
    
    move(metros: number = 0) {
        console.log(this.nome + " moveu " + metros + "m");
    }

    static origin = new Animal("Origem", 0);
}

var a = new Animal("Cachorro", 2);
a.move(10); // Cachorro moveu 10m
a.origin; // Origem moveu 0m
a.origin.move(0); // Origem moveu 0m
var b = new Animal("Gato");
console.log(b.idade); // idade é 0

Herança:


class Cachorro extends Animal {
    latir() {
        console.log("Au au!");
    }
}

var c = new Cachorro("Rex", 3);
c.move(10); // Rex moveu 10m
c.latir(); // Au au!

class Gato extends Animal {
    constructor(nome: string, idade: number, public cor: string) {
        super(nome, idade);
    }
    miar() {
        console.log("Miau!");
    }
}

var g = new Gato("Mingau", 1, "preto");
g.move(5); // Mingau moveu 5m
g.miar(); // Miau!

class Point {
    x: number;

    constructor(x: number, public y: number = 0) {
        this.x = x;
    }

    dist() { return Math.sqrt(this.x * this.x + this.y * this.y); }
    static origin = new Point(0, 0);
}

var p1 = new Point(10 ,20);
var p2 = new Point(25);

// Herança
class Point3D extends Point {
    constructor(x: number, y: number, public z: number = 0) {
        super(x, y);
    }

    // Sobrescrever
    dist() {
        var d = super.dist();
        return Math.sqrt(d * d + this.z * this.z);
    }
}

var p3 = new Point3D(10, 20, 30);
console.log(p3.dist()); // 37.416573867739416
console.log(Point.origin); // Point { x: 0, y: 0 }
console.log(Point3D.origin); // Point { x: 0, y: 0 }
console.log(Point3D.origin.dist()); // 0
console.log(Point3D.origin.z); // undefined
console.log(Point3D.origin.x); // 0

Módulos:


module Geometry {
  export class Square {
    constructor(public sideLength: number = 0) {
    }
    area() {
      return Math.pow(this.sideLength, 2);
    }
  }
}

var s1 = new Geometry.Square(5); // 25 ("." pode ser utilizado como separador de sub módulos)

import G = Geometry; // Alias no local para fazer referência a um módulo
var s2 = new G.Square(10);
console.log(s2.area()); // 100
console.log(G.Square); // [Function: Square]
console.log(G.Square.prototype.area); // [Function: area]
console.log(G.Square.prototype.area()); // NaN
console.log(G.Square.prototype.area.call(s2)); // 100
console.log(G.Square.prototype.area.call(G.Square(5))); // NaN

// Export:
export interface StringValidator {
    isAcceptable(s: string): boolean;
}

export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5;
    }
}

const validator = new ZipCodeValidator();

const testStrings = ["12345", "abcd", "678", "987654"];
testStrings.forEach((testString) => {
    console.log(`"${testString}" é aceitável? ${validator.isAcceptable(testString)}`);
});

// Import:
import { ZipCodeValidator } from "./ZipCodeValidator";

let myValidator = new ZipCodeValidator();
let testStrings = ["12345", "9876", "ABCDE", "54321"];

testStrings.forEach((testString) => {
    console.log(`"${testString}" é aceitável? ${myValidator.isAcceptable(testString)}`);
});

Genéricos:


function retornaElemento<T>(elemento: T): T {
  return elemento;
}

const numero = retornaElemento<number>(42);
const texto = retornaElemento<string>("Olá, TypeScript!");

console.log(numero); // 42
console.log(texto); // Olá, TypeScript!
console.log(retornaElemento<boolean>(true)); // true

// Classes
class Tuple<T1, T2> {
    constructor(public item1: T1, public item2: T2) {
    }
}

var t = new Tuple<number, string>(1, "Hello");
console.log(t.item1); // 1
console.log(t.item2); // Hello
console.log(t); // Tuple { item1: 1, item2: 'Hello' }

// Interfaces
interface Pair<T> {
    item1: T;
    item2: T;
}

console.log({ item1: 1, item2: 2 } as Pair<number>); // { item1: 1, item2: 2 }
console.log({ item1: "Hello", item2: "World" } as Pair<string>); // { item1: 'Hello', item2: 'World' }

// Funções
var pairToTuple = function<T>(p: Pair<T>) {
    return new Tuple(p.item1, p.item2);
};

var tuple = pairToTuple({ item1:"hello", item2:"world"});
console.log(tuple); // Tuple { item1: 'hello', item2: 'world' }

Union Types:


function imprimirId(id: number | string): void {
  console.log(`ID: ${id}`);
}

imprimirId(123);
imprimirId("abc123");

Intersection Types:


interface A {
    a: number;
}

interface B {
    b: number;
}

type AB = A & B;

function imprimirAB(ab: AB): void {
    console.log(`A: ${ab.a}, B: ${ab.b}`);
}

imprimirAB({ a: 1, b: 2 }); // A: 1, B: 2

Type Assertions:


let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength2: number = (someValue as string).length;

console.log(`Valor de someValue: "${someValue}"`);
console.log(`Comprimento da string (usando <string>): ${strLength}`);
console.log(`Comprimento da string (usando as string): ${strLength2}`);

Literal/Aliases Types:


type Direction = "left" | "right" | "up" | "down";

function move(direction: Direction): void {
    console.log(`Moving ${direction}`);
}

move("left"); // Moving left
move("right"); // Moving right
move("up"); // Moving up
move("down"); // Moving down

type ID = number | string;

let meuId: ID = 123;
meuId = "abc";

Utility Types:


// Partial:
interface User {
    id: number;
    name: string;
    age: number;
}

let partialUser: Partial<User> = {
    name: "Alice",
};

console.log("Objeto parcial de User:");
console.log(`Nome: ${partialUser.name}`);
console.log(`ID: ${partialUser.id ?? "não definido"}`);
console.log(`Idade: ${partialUser.age ?? "não definida"}`);

// Readonly:
interface User {
    id: number;
    name: string;
    age: number;
}

let readonlyUser: Readonly<User> = {
    id: 1,
    name: "Bob",
    age: 25,
};

// readonlyUser.age = 26; // Error: cannot reassign a readonly property
console.log("Objeto Readonly<User>:");
console.log(`ID: ${readonlyUser.id}`);
console.log(`Nome: ${readonlyUser.name}`);
console.log(`Idade: ${readonlyUser.age}`);

// Pick:
interface User {
    id: number;
    name: string;
    age: number;
}

type UserName = Pick<User, "name">;

let userName: UserName = {
    name: "Charlie",
};

console.log("Objeto UserName:");
console.log(`Nome: ${userName.name}`);

// Omit:
interface User {
    id: number;
    name: string;
    age: number;
}

type UserWithoutAge = Omit<User, "age">;

let userWithoutAge: UserWithoutAge = {
    id: 2,
    name: "Dave",
};

console.log("Objeto UserWithoutAge:");
console.log(`ID: ${userWithoutAge.id}`);
console.log(`Nome: ${userWithoutAge.name}`);

Enum:


enum Cor {
    Vermelho = "Red",
    Azul = "Blue",
    Verde = "Green",
}

const minhaCor: Cor = Cor.Vermelho;
console.log(minhaCor); // Output: "Red"

Decorators:


// Class Decorator:
function sealed(constructor: Function) {
    console.log("Sealing constructor:", constructor.name);
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

@sealed
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
        console.log("Greeter constructor called with message:", message);
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

console.log("Greeter class:", Greeter);
const greeterInstance = new Greeter("world");
console.log("Greeter instance:", greeterInstance);
console.log("Greet method output:", greeterInstance.greet());


// Method Decorator:
function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log(`Setting enumerable to ${value} for method: ${propertyKey}`);
        descriptor.enumerable = value;
    };
}

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
        console.log("Greeter constructor called with message:", message);
    }

    @enumerable(false)
    greet() {
        return "Hello, " + this.greeting;
    }
}

console.log("Greeter prototype:", Object.getPrototypeOf(Greeter));

const greeterInstance = new Greeter("world");
console.log("Greeter instance:", greeterInstance);
console.log("Greet method output:", greeterInstance.greet());

console.log(
    "Is greet enumerable?",
    Object.prototype.propertyIsEnumerable.call(greeterInstance, "greet")
);

console.log("Enumerable properties of Greeter instance:", Object.keys(greeterInstance));

console.log(
    "All properties of Greeter prototype:",
    Object.getOwnPropertyNames(Object.getPrototypeOf(greeterInstance))
);


// Async/Await Decorator:
async function fetchData(url: string) {
    console.log("Fetching data from URL:", url);
    let response = await fetch(url);
    console.log("Response status:", response.status);
    let data = await response.json();
    console.log("Data received:", data);
    return data;
}

const testFetchData = async () => {
    try {
        const url = "https://jsonplaceholder.typicode.com/todos/1";
        console.log("Starting fetchData test...");
        const result = await fetchData(url);
        console.log("Final result from fetchData:", result);
    } catch (error) {
        console.error("Error during fetchData:", error);
    }
};

testFetchData();

Namespaces:


namespace Geometry {
    export interface Vector2D {
        x: number;
        y: number;
    }

    export interface Vector3D {
        x: number;
        y: number;
        z: number;
    }
}

const vector2D: Geometry.Vector2D = { x: 1, y: 2 };
const vector3D: Geometry.Vector3D = { x: 1, y: 2, z: 3 };

console.log(vector2D); // { x: 1, y: 2 }
console.log(vector3D); // { x: 1, y: 2, z: 3 }

Referência de arquivo:

Pode ocorrer via export/import, ou via reference (exemplo abaixo).


utils.ts:
function greet(name: string): string {
  return `Hello, ${name}!`;
}

app.ts:
///<reference path="./utils.ts" />
console.log(greet("Alice"));


Cheat Sheets:










Projeto prático (To-Do List):

  1. Criar projeto:
    
    mkdir to-do-list
    cd to-do-list
    mkdir src src/models src/services
    npm init -y
    npm install --save-dev typescript
    npm install --save-dev @types/node
    npx tsc --init
    
  2. Editar arquivo tsconfig.json:
    
    {
        "compilerOptions": {
            "target": "ES6",
            "module": "commonjs",
            "outDir": "./dist",
            "rootDir": "./src",
            "strict": true,
            "esModuleInterop": true
        },
        "include": ["src/**/*"]
    }
    
  3. Arquivo src/models/Task.ts:
    
    export interface Task {
        id: number;
        title: string;
        completed: boolean;
        createdAt: Date;
    }
    
  4. Arquivo src/services/TaskService.ts:
    
    import { Task } from "../models/Task";
    
    export class TaskService {
        private tasks: Task[] = [];
        private nextId: number = 1;
    
        addTask(title: string): Task {
            const newTask: Task = {
                id: this.nextId++,
                title,
                completed: false,
                createdAt: new Date(),
            };
            this.tasks.push(newTask);
            return newTask;
        }
    
        listTasks(): Task[] {
            return this.tasks;
        }
    
        completeTask(id: number): boolean {
            const task = this.tasks.find((task) => task.id === id);
            if (task) {
                task.completed = true;
                return true;
            }
            return false;
        }
    
        removeTask(id: number): boolean {
            const index = this.tasks.findIndex((task) => task.id === id);
            if (index !== -1) {
                this.tasks.splice(index, 1);
                return true;
            }
            return false;
        }
    }
    
  5. Arquivo src/index.ts:
    
    import { TaskService } from "./services/TaskService";
    
    const taskService = new TaskService();
    
    console.log("Adicionando tarefas:");
    const task1 = taskService.addTask("Estudar TypeScript");
    const task2 = taskService.addTask("Desenvolver um projeto");
    console.log(task1);
    console.log(task2);
    
    console.log("\nLista de tarefas:");
    console.log(taskService.listTasks());
    
    console.log("\nConcluindo a tarefa com ID 1:");
    taskService.completeTask(1);
    console.log(taskService.listTasks());
    
    console.log("\nRemovendo a tarefa com ID 2:");
    taskService.removeTask(2);
    console.log(taskService.listTasks());
    
  6. Compilar e executar:
    
    npx tsc
    node dist/index.js
    
  7. (Opcional) Adicionar Scripts ao package.json:
    
    "scripts": {
        "build": "tsc",
        "start": "node dist/index.js"
    }
    
    • Compilar: npm run build
    • Executar: npm start

Elaborado por Mateus Schwede
ubsocial.github.io