Angular

TypeScript

Introdução

  • Typescript é uma linguagem criada e mantida pela Microsoft;

  • A linguagem foi pensada para o desenvolvimento de código JavaScript em larga escala (milhões de linhas de código);

Introdução

  • O Visual Studio Code (300 mil linhas de código) e o Azure Management Portal (1,2 milhões de linhas de código) foram desenvolvidos em TypeScript;

  • TypeScript oferece ferramentas para design, checagem em tempo de compilação e carregamento de módulos dinâmicos em tempo de execução.

TypeScript: Components

  • Linguagem: consiste da nova sintaxe, palavra chaves e anotações de tipo, esta será mais utilizada por nós programadores, entender essa parte é fundamental para entender como usar os serviços e o compilador de forma mais efetiva.

TypeScript: Components

  • Compilador: realiza as transformações que convertem o código TypeScript em JavaScript. Irá emitir erros e avisos se encontrar problemas, e pode realizar tarefas adicionais como combinar várias saídas em um único arquivo, gerar Source Maps e muito mais.

TypeScript: Components

  • Linguagem de Serviço: oferece informações de tipo que podem ser usadas por ferramentas de desenvolvimento para prover auto-complete, dica de tipos e opções de refatoração, assim como outras formas de funcionalidades baseadas no tipo de informação encontrada no seu código.

Compilar ou transpilar

  • Compilação: é o processo de converter um código fonte de uma linguagem e transformar em outra linguagem;

  • Transpilação: é o processo de pegar o código de uma linguagem e transforma em outra linguagem que tenha um nível de abstração similar;

Problemas que typeScript Resolve

Apesar da popularidade de JavaScript, existem sérios problemas com a linguagem, muitas “armadilhas e ciladas” que podem prejudicar uma grande aplicação, se vocês já trabalharam com programas complexos feitos em JavaScript, a chance de ter que encontrado problemas com conflito de nomes, modularização complexa, herança que torna o reuso de simples design patterns extremamente difícil, além de ser difícil ler e manter a base de código. TypeScript surge para resolver ou amenizar alguns desses problemas.

Herança Prototípica

Programação orientada a protótipo é um tipo de OOP em que o reuso (herança) é feito através do processo de reusar objetos existente via delegação. Cada objeto é um protótipo para criação de outros objetos.

Herança Prototípica

var a = 1;

function seven() {
  this.a = 7;
}

seven.prototype.a = -1;

seven.prototype.b = 8;

alert(new seven().a); // mostra '7'
alert(new seven().b); // mostra '8'

Herança Prototípica: TypeScript

TypeScript resolve esse problema, adicionando classes, namespaces, módulos e interfaces. Isso permite que programadores possam aplicar o conhecimento existente de orientação a objetos e estrutura de código de outras linguagem. Incluindo implementação de interfaces, heranças ao modelo de organização de código existente.

Igualdade e manipulação de tipos

JavaScript sempre foi capaz de lidar com tipos de variáveis dinâmicas, como resultado gasta-se recurso em tempo de execução trabalhando com tipos e forçando tipo as se transformarem em outros tipo, para fazer com que os statements funcionem, caso isso fosse implementado numa linguagem estática, resultaria em erro.

Igualdade e manipulação de tipos

Uma das formas mais comuns de forçar um tipo a mudar, é quando usamos concatenação envolvendo, string, numbers e booleans. Se concatenamos uma string com um valor, o valor será convertido para string. Se fazemos uma operação matemática, será feita uma tentativa de transformar o valor em um número.

Igualdade e manipulação de tipos

Em alguns casos isso pode ser uma característica desejada, em outros casos isso pode trazer problemas e uma manipulação de dados de forma incorreta pode causar um comportamento não desejado.

Igualdade e manipulação de tipos

let a = "0";
let b = "0";
let c = a/b;
console.log(c);
let d = true;
let e = c && d;
console.log(e);
let a = "1";
let b = "0";
let c = a/b;
console.log(c);
let d = true;
let e = c && d;
console.log(e);

Igualdade e manipulação de tipos

let a = "10";
let b = "20";
let c = "30";
let d = a + b * c;
let e = (a + b) * c;
console.log(d);
console.log(e);
let a = 10;
let b = 20;
let c = 30;
let d = a + b * c;
let e = (a + b) * c;
console.log(d);
console.log(e);

Igualdade e manipulação de tipos

JavaScriptTypescript
let numero = 1;
let palavra= '0';

let stringNumero =
    numero + palavra;

let resultado =
    stringNumero * 2;

console.log(stringNumero, resultado)
let numero: number = 1;
let palavra: string = '0';

let stringNumero: number =
    numero + palavra;

let resultado: number =
    stringNumero * 2;

console.log(stringNumero, resultado)

Igualdade e manipulação de tipos: TypeScript

TypeScript resolve isso introduzindo a checagem de tipo, que exibe mensagens de aviso enquanto você codifica ou em tempo de compilação, para informar sobre uma potencial manipulação de tipos, isso previne pressupostos que podem ser potencialmente perigosos a passarem despercebidos.

Gerenciamento de Módulos

Problemas comuns de dependência em JavaScript:

  • Esquecer de adicionar uma script tag em uma página web;

  • Ver que você adicionou script tags que não são usadas;

  • Adicionar scripts em uma página na ordem errada;

  • Encontrar o local do erro em sistemas grandes;

Gerenciamento de Módulos

Problemas comuns de dependência em JavaScript:

  • Combinar vários scripts em um único script na ordem errada;

  • Tentar depurar scripts que foram combinados ou minificados;

  • Descobrir que a ferramenta de minificação não suporta alguma funcionalidade da linguagem;

Gerenciamento de Módulos: TypeScript

No entanto, o TypeScript faz com que os carregadores de módulos sejam o modo de trabalho padrão e permita que seus módulos sejam compilados para se adequar aos estilos de carregamento do módulo mais prevalentes, sem exigir alterações ao seu código.

Escopo

Na maioria das linguagens semelhante a C, as chaves criam um novo contexto para o bloco, ou seja uma variável declarada dentro de um bloco não pode ser vista fora desse bloco. O JavaScript curvou essa tendência tradicionalmente por possuir escopo funcional, o que significa que os blocos definidos por chaves não têm efeito no escopo. Em vez disso, as variáveis são dimensionadas para a função em que foram declaradas ou o escopo global se não forem declaradas dentro de uma função.

Escopo

Podem haver mais complicações causadas pela omissão acidental da palavra-chave var dentro de uma função, promovendo assim a variável para o escopo global.

Mais complicações são causadas por elevação de variável, resultando em todas as variáveis dentro de uma função se comportam como se fossem declaradas na parte superior da função.

Escopo

var teste = 100;

function teste1() {
  console.log(teste);
}

function teste2() {
  console.log(teste);
  var teste = 111;
  console.log(teste);
}

teste1();
teste2();

Escopo

O ES6 Introduz efeitos de escopo em chaves no javascript com o uso do bloco let ou const.

var teste = 100;

function teste3() {
  console.log(teste);
  let teste = 111;
  console.log(teste);
}

teste3();

Escopo

Apesar de algumas surpresas complicadas com escopo, o JavaScript fornece um mecanismo poderoso que envolve o atual alcance lexical em torno de uma declaração de função para manter os valores à mão quando a função é executada mais tarde. Uma das características mais poderosas do JavaScript.

Escopo: TypeScript

O TypeScript facilita os problemas de escopo alertando sobre variáveis globais implícitas, desde que você evite adicionar variáveis ao escopo global.

Falta de tipos

O problema com JavaScript não é que não tenha nenhum tipo, porque cada variável possui um tipo; É apenas que o tipo pode ser alterado a qualquer momento. Uma variável pode começar como uma string, mas uma função pode alterá-la para um número, um objeto ou até uma outra função. O problema real aqui é que as ferramentas de desenvolvimento não podem ser melhoradas além de mostrar uma estimativa razoável sobre o tipo de variável.

Falta de tipos: Typescript

Se as ferramentas de desenvolvimento não conhecem os tipos, o auto-complete e dica de tipo (type hint) geralmente são muito gerais para serem úteis. Por meio da formalização de informações de tipo, o TypeScript permite que ferramentas de desenvolvimento forneçam ajuda contextual específica que, de outra forma, não seria possível.

Sumário

O TypeScript é uma linguagem de programação de escala de aplicação que fornece acesso antecipado a novos recursos de JavaScript propostos e recursos adicionais poderosos como verificação de tipo estático. Você pode escrever programas TypeScript para executar em navegadores da Web ou em servidores e você pode reutilizar o código entre o navegador e os aplicativos do servidor. O TypeScript resolve muitos problemas em JavaScript, mas respeita os padrões e a implementação da linguagem JavaScript, por exemplo a capacidade de ter tipos dinâmicos.

Sumário

Você pode usar muitos ambientes de desenvolvimento integrados com TypeScript, com vários provedores de suporte de primeira classe incluindo verificação de tipo e preenchimento automático que melhorarão sua produtividade e ajudarão a eliminar erros em tempo de design.

Tipos Básicos

  • number

  • boolean

  • string

  • null

  • undefined

  • any

Tipos Básicos: boolean

let sim: boolean = true;
let nao: boolean = false;

console.log(sim, nao);

Tipos Básicos: number

let decimal: number = 6;
let float: number = 6.1;
let hex: number = 0xa00d;
let binary: number = 0b1001;
let octal: number = 0o111;

console.log(decimal, float, octal, binary, octal);

Tipos Básicos: string

let treinamento: string = `TypeScript`;
let sentence: string = `Esse é o treinamento de ${treinamento} e Angular`

console.log(sentence);

Tipos Básicos: array

let lista: number[] = [1, 2, 3];

console.log(lista[0]);

lista.forEach( (item) => console.log(item) );

lista.push(4);

lista.forEach( (item) => console.log(item) );

Tipos Básicos: tuple

let x: [string, number];
x = ["hello", 10];
console.log(x[0].substr(1));
console.log(x[1]);
// Erros
x = [10, "hello"];
console.log(x[1].substr(1));
x[3] = "world";

Tipos Básicos: enum

enum Cor {Vermelho, Verde, Preto}
let cor: Cor = Cor.Verde;

console.log(cor);
enum Cor {Vermelho = 1, Verde, Preto}

let corNome: string = Cor[2];

console.log(corNome);

Tipos Básicos: any

let qualquer: any = "teste";

console.log(qualquer);

qualquer = 10;

console.log(qualquer);

qualquer.teste(); // erro

Tipos Básicos: null e undefined

let teste: any | number | string;

let n: null = null;
let u: undefined = teste;

console.log(({} as any).teste);

let teste2: number;

teste2 = undefined;
teste2 = null;

console.log(teste2);

Tipos Básicos: void

function imprimir(): void {
    console.log("Mensagem");
}

let unusable: void = undefined;
unusable = null;
unusable = 10;

unusable = imprimir();

Tipos Básicos: never

function error(): never {
    throw new Error();
}

function loop(): never {
    while (true) {
    }
}

let nunca: never = error();
let nunca2: any = error();

Tipos Básicos: object e Object

let objeto: Object = 10;
objeto.teste = 10;

let naoPrimitivo: object = {};
naoPrimitivo = 10;

Tipos Básicos: type assertions

let someValue: Object = "this is a string";
let strLength: number;

strLength = (<string>someValue).length;
strLength = (someValue as string).length;
strLength = someValue.length

Declaração de variáveis: var, let e const

for (var i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log("var: " + i); }, 100 * i);
}
for (let i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log("let: " + i); }, 100 * i);
}
const constante = 10;
constante = 1;

Declaração de variáveis: Inferência de tipos

let dummy;
let num = 10;
let str = "Hello TypeScript";
let bln = true;
let stringArray = ["Homer", "Simpson"];
num = "teste";

Declaração de variáveis: Destructuring em arrays

let input = [1, 2];
let [first, second] = input;
console.log(first, second);
[first, second] = [second, first];
console.log(first, second);
let [first, ...rest] = [1, 2, 3, 4];
console.log(first, rest);
let [, second, , fourth] = [1, 2, 3, 4];
console.log(second, fourth);

Declaração de variáveis: Destructuring em objetos

let o = { a: "foo", b: 12, c: "bar"};
let { a, b } = o;

({ a, b } = { a: "baz", b: 101 });

Declaração de variáveis: Destructuring em objetos

let o = { a: "foo", b: 12, c: "bar"};
let { a, ...passthrough } = o;
console.log(a, passthrough);
let total = passthrough.b + passthrough.c.length;
console.log(total);

let { a: newName1, b: newName2 } = o;
console.log(newName1, newName2);

function keepWholeObject(wholeObject: { a: string, b?: number }) {
    let { a, b = 1001 } = wholeObject;
    console.log(a, b);
}
keepWholeObject(o);
keepWholeObject({ a: "teste" });

Declaração de variáveis: Spread

let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];
console.log(bothPlus);

let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { ...defaults, food: "rich" };
console.log(search);

let defaults2 = { food: "spicy", price: "$$", ambiance: "noisy" };
let search2 = { food: "rich", ...defaults };
console.log(search2);

Declaração de variáveis: Spread

class C {
  p = 12;
  m() {
  }
}
let c = new C();
let clone = { ...c };

console.log(c, clone);

clone.p;
clone.m(); // erro

Interfaces

interface Usuario {
    nome: string;
    sobrenome?: string;
    readonly leitura?: string;
    [propName: string]: any;
}
function hello(person: Usuario): string
{
        return "Hello, " + person.nome;
}

let usuario: Usuario = { nome: "Jane User",  sobrenome: "Jane User 2"};

usuario.teste = "teste";

console.log(hello(usuario));

Interfaces

class Control {
    private state: any;
}
interface SelectableControl extends Control {
    select(): void;
}
class Button extends Control implements SelectableControl {
    select() { }
}
class TextBox extends Control {
    select() { }
}

// Erro
class Image implements SelectableControl {
    private state: any;
    select() { }
}

Interfaces

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

Classes

interface Usuario {
        nome: string;
        sobrenome: string;
}
class UsuarioI implements Usuario {
    public sobrenome: string;
    constructor(public nome: string) { }
    public hello(person: Usuario): string {
        return "Hello, " + person.nome;
    }
}
let usuario = new UsuarioI("User");
console.log(usuario.hello(usuario));

Classes: constructor

class Usuario {
    private login: string;
    constructor(
        public nome: string,
        public sobrenome: string = "teste",
        public cpf?: string) {
            this.login = nome;
    }
}
let usuario = new Usuario("teste");
console.log(usuario);

Classes: Herança

class Animal {
    move(distanceInMeters: number = 0) {
        console.log(`Animal moved ${distanceInMeters}m.`);
    }
}
class Dog extends Animal {
    bark() {
        console.log('Woof! Woof!');
    }
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();

Classes: super e this

class Animal {
    move(distanceInMeters: number = 0) {
        console.log(`Animal moved ${distanceInMeters}m.`);
    }
}
class Dog extends Animal {
    private bark = "Woof! Woof!";
    move(distanceInMeters: number = 0) {
        console.log(this.bark);
        super.move(distanceInMeters);
    }
}
const dog = new Dog();
dog.move(10);

Classes: Modificadores de acesso

  • Public (padrão): Podem ser acessados de qualquer local.

  • Private: Não podem ser acessados fora da classe de declaração.

  • Protected: Só podem ser acessados por classes derivadas.

Classes: Modificadores de acesso

class Usuario {
    public nome: string;
    private apelido: string;
    constructor(protected sobrenome: string = "Teste") {
    }
    protected teste() {
        console.log("teste");
    }
}

let usuario = new Usuario();
usuario.teste();
usuario.nome;
usuario.sobrenome;

Classes: static e abstract

abstract class Animal {
    abstract makeSound(): void;
    static move(): void {
        console.log("roaming the earth...");
    }
}
class Dog extends Animal {
    public makeSound(): void {
        console.log("bark...");
    }
}

Animal.move()

let dog = new Dog();
dog.makeSound();

let animal = new Animal();

Classes: get e set

class Animal {
    private _nome;

    get nome() {
        return this._nome;
    }

    set nome(nome: string) {
        this._nome = nome;
    }
}
let animal = new Animal();
animal.nome = "teste";
console.log(animal.nome);

Funções

function funcao(
    arg1: string,
    arg2: string = "argDefault",
    arg3?: string,
    ...rest: string[]): string {
    return `${arg1} ${arg2} ${arg3 ? arg3 : ''} ${rest.join(" ")}`;
}

let funcaoVariavel:
    (
        a1: string,
        a2?: string,
        a3?: string,
        ...a4: string[]
    ) => string = funcao;

console.log(funcaoVariavel('arg1'));
console.log(funcaoVariavel('arg1', "arg2"));
console.log(funcaoVariavel('arg1', "arg2", "arg3"));
console.log(funcaoVariavel('arg1', "arg2", "arg3", "arg4", "arg5", "arg6"));

Funções: Arrow function

let funcaoVariavel: (
    a1: string,
    a2?: string,
    a3?: string,
    ...a4: string[]) => string =
    (
        arg1: string,
        arg2: string = "argDefault",
        arg3?: string,
        ...rest: string[]
    ) => `${arg1} ${arg2} ${arg3 ? arg3 : ''} ${rest.join(" ")}`;

console.log(funcaoVariavel('arg1'));
console.log(funcaoVariavel('arg1', "arg2"));
console.log(funcaoVariavel('arg1', "arg2", "arg3"));
console.log(funcaoVariavel('arg1', "arg2", "arg3", "arg4", "arg5", "arg6"));

Funções: this

class Navegador {
    private navigator = { appName: "Exemplo" };
    imprimeNome(): void {
        console.log(this.navigator.appName);
    }
}

let navegador = new Navegador();
navegador.imprimeNome();

let imprimeNome = navegador.imprimeNome;

imprimeNome();
imprimeNome.call(navegador);

Funções: sobrecarga

function funcao(arg1: string, arg2: number): string;
function funcao(arg1: string, arg2: string): string;
function funcao(arg1: string, arg2: any): string {
    return `${arg1} ${arg2}`;
}

console.log(funcao("arg1", 19));
console.log(funcao("arg1", "arg2"));
console.log(funcao("arg1", true));

Generics: funções

function funcao<T>(teste: T): T[];
function funcao<T>(...rest: T[]): T[] {
    return rest;
}

let funcaoVariavel1: { <T>(arg: T): T[] } = funcao;
let funcaoVariavel2: <T>(arg: T) => T[] = funcao;

console.log(funcao<string>("teste"));
console.log(funcao<number>(100));
console.log(funcao<number>("100"));

Generics: classes

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

console.log(myGenericNumber.add(1, 2));

Generics: extends e keyof

interface Lengthwise {
    length: number;
}
function logging<T extends Lengthwise>(arg: T): void {
    console.log(arg.length);
}
logging({length: 10, value: 3});
logging(100);

function getProperty<T, K extends keyof T>(obj: T, key: K): void {
    console.log(obj[key]);
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a");
getProperty(x, "m");

Generics: factories

class Animal {
    numLegs: number;
}

class Bee extends Animal {
    bee: string;
}

class Lion extends Animal {
    lion: string;
}

function createInstance<A extends Animal>(c: new () => A): A {
    return new c();
}

createInstance(Lion).lion;
createInstance(Bee).bee;

Tipos tópicos avançados: Structural typed vs nominally-typed

interface Named {
    name: string;
}

class Person {
    name: string;
}

let p: Named;
p = new Person();

Tipos tópicos avançados: Structural typed vs nominally-typed

let x = (a: number) => 0;
let y = (b: number, s: string) => 0;

y = x;
x = y;
let x = () => ({name: "Alice"});
let y = () => ({name: "Alice", location: "Seattle"});

x = y;
y = x;

Tipos tópicos avançados: Structural typed vs nominally-typed

class Animal {
    feet: number;
    constructor(name: string, numFeet: number) { }
}

class Size {
    feet: number;
    constructor(numFeet: number) { }
    static teste(teste: string) {}
}

class Other {
    private feet: number;
}


let a: Animal;
let s: Size;
let o: Other;

a = s;
s = a;
a = o;
o = a;

Tipos tópicos avançados: Structural typed vs nominally-typed

interface Empty<T> {
}
let x: Empty<number>;
let y: Empty<string>;

x = y;

interface NotEmpty<T> {
    data: T;
}
let z: NotEmpty<number>;
let h: NotEmpty<string>;

z = h;

Tipos tópicos avançados: intersection type

class Person {
    public name: string;
}

interface Loggable {
    log(name: string): void;
}

let loggablePerson: Person & Loggable =
{
    name: "teste",
    log: (name: string) => console.log("teste")
};

let loggablePerson2: Person & Loggable =
{
    name: "teste",
};

Tipos tópicos avançados: union type

class Person {
    public name: string;
}

interface Loggable {
    log(name: string): void;
}

let loggablePerson: Person | Loggable =
{
    name: "teste",
    log: (name: string) => console.log("teste")
};

let loggablePerson2: Person | Loggable =
{
    name: "teste",
};

Tipos tópicos avançados: type guard

class Person {
    public name: string;
}

let pessoa = new Person();

console.log(pessoa.name === undefined);
console.log(pessoa.name === null);
console.log(typeof pessoa.name === "string");
pessoa.name = "teste";
console.log(typeof pessoa.name === "string");
console.log(pessoa instanceof Person);

Tipos tópicos avançados: type alias e literal type

class Person {
    name: "Nome1" | "Nome2" | 1;
}
type Pessoa = Person;

let pessoa: Pessoa = new Person();
pessoa.name = "Nome1";
pessoa.name = 1;
pessoa.name = "Teste";

Interações

let list = [4, 5, 6];

for (let i in list) {
   console.log(i);
}

for (let i of list) {
   console.log(i);
}

Decorators

function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

@classDecorator
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

Módulos - export

// Validation.ts
export interface StringValidator {
    isAcceptable(s: string): boolean;
}

// ZipCodeValidator.ts
export const numberRegexp = /^[0-9]+$/;

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

Módulos - export

// ZipCodeValidator.ts
class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };

// validator.ts
export * from "./StringValidator"; // exports interface 'StringValidator'
export * from "./LettersOnlyValidator"; // exports class 'LettersOnlyValidator'
export * from "./ZipCodeValidator";  // exports class 'ZipCodeValidator'

Módulos - import

// Único import
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator = new ZipCodeValidator();

// Renomeando import
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();

// Importando todo o arquivo
import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();

Módulos - default import

// JQuery.d.ts
declare let $: JQuery;
export default $;

// App.ts
import $ from "JQuery";
$("button.continue").html( "Next Step..." );

Módulos - namespaces

// shapes.ts
namespace Shapes {
    export namespace Polygons {
        export class Triangle { }
        export class Square { }
    }
}

import polygons = Shapes.Polygons;
let sq = new polygons.Square();

// shapeConsumer.ts
import * as shapes from "./shapes";
let t = new shapes.Shapes.Polygons.Triangle();

Referências

Dúvidas

Alguma pergunta?