{"id":27644191,"url":"https://github.com/maiconwte/starting-typescript","last_synced_at":"2025-11-04T09:05:24.977Z","repository":{"id":123506674,"uuid":"266897581","full_name":"maiconwte/starting-typescript","owner":"maiconwte","description":"A typescript guide for beginners :seat:","archived":false,"fork":false,"pushed_at":"2020-06-10T13:36:18.000Z","size":60,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-15T12:56:06.575Z","etag":null,"topics":["begginers","javascript","typescript"],"latest_commit_sha":null,"homepage":"https://www.maiconsilva.com/starting-typescript/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maiconwte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-05-25T23:08:56.000Z","updated_at":"2024-05-24T02:06:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"b00bdeff-969f-48b1-8974-201317ce25f6","html_url":"https://github.com/maiconwte/starting-typescript","commit_stats":null,"previous_names":["maiconwte/starting-typescript"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maiconwte%2Fstarting-typescript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maiconwte%2Fstarting-typescript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maiconwte%2Fstarting-typescript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maiconwte%2Fstarting-typescript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maiconwte","download_url":"https://codeload.github.com/maiconwte/starting-typescript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250536526,"owners_count":21446749,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["begginers","javascript","typescript"],"created_at":"2025-04-24T00:23:55.883Z","updated_at":"2025-11-04T09:05:24.928Z","avatar_url":"https://github.com/maiconwte.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Introdução - O que é o TypeScript?\n\nÉ um superset do JavaScript criado pela Microsoft. o TS adiciona features como tipagem estática ao JavaScript e necessita ser transpilado para ser utilizado no browser ou até mesmo no nodejs.\n\n## Por que usar TypeScript?\n\nJavaScript é uma linguagem dinâmica, com isso podemos(sem querer?) mudar o tipo das variáveis e obter retornos inesperados.\n\n```javascript\nfunction sum(a, b) {\n    return a + b;\n}\n\nsum(10, 10); // 20\nsum('2', '2'); // 22? concatenou a string :D\n```\n\nO TypeScript nos avisa em casos como esse e também em muitos outros.\n\nTambém podemos usar o TS como uma \"documentação\". Por exemplo, imagine uma propriedade em um objeto\nque deve receber um array, mas esse array só pode ser preenchido com uma determinada string ou valor.\nPara isso temos o `type`:\n\n```javascript\ntype Platform = 'Windows' | 'Mac OS' | 'Linux';\ntype Feature = 'Single Player' | 'Multiplayer' | 'Co-op';\n\ninterface GameDetails {\n    id: string;\n    title: string;\n    description: string;\n    platforms: Platform[];\n    features: Feature[];\n}\n```\n\nPlatforms e features em `GameDetails` são arrays que esperam os valores presente em seus respectivos types.\n\n## Primeiro código em TypeScript\n\nPara transpilar o código TS para JS, utilizamos o [tsc](https://www.typescriptlang.org/#installation), então é necessário instala-lo:\n\n```shell\nnpm install -g typescript\n```\n\nVários editores são compatíveis com o TypeScript. O mais importante é a integração com a linguagem, para que o editor possa identificar os erros, ler as APIs etc.\n\nVamos usar um exemplo de uma página que soma dois números:\n\n`index.html`\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n    \u003ctitle\u003eSum\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cinput type=\"number\" id=\"num1\"\u003e\n    \u003cspan\u003e+\u003c/span\u003e\n    \u003cinput type=\"number\" id=\"num2\"\u003e\n\n    \u003cbutton id=\"button\"\u003eSomar\u003c/button\u003e\n\n    \u003cscript src=\"./somar.js\"\u003e\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n`somar.js:`\n\n```javascript\nconst input1 = document.getElementById('num1');\nconst input2 = document.getElementById('num2');\nconst button = document.getElementById('button');\n\nfunction sum(a, b) {\n    return a + b;\n}\n\nbutton.addEventListener('click', function() {\n    console.log(sum(input1.value, input2.value));\n});\n```\n\nA saída do click nunca vai ser a soma dos números, pois input.value retorna uma string. O retorno da função no exemplo acima é os valores concatenados, em vez de somados, como esperado.\n\nAgora o mesmo código em TypeScript:\n\n\u003e Arquivos em TypeScript devem possuir a extensão .TS\n\n`somar.ts:`\n\n```typescript\nconst input1 = document.getElementById('num1') as HTMLInputElement;\nconst input2 = document.getElementById('num2') as HTMLInputElement;\nconst button = document.getElementById('button');\n\nfunction sum(a: number, b: number) {\n    return a + b;\n}\n\nbutton.addEventListener('click', function() {\n    console.log(sum(input1.value, input2.value));\n});\n```\n\nPara acessar a propriedade value do input sem o TS detectar um erro, foi necessário tipar a variável `input1` e `input2` como um `HTMLInputElement`.\n\nTambém é possível ver a tipagem na função `sum`. O código acima irá retornar erro ao chamar a função `sum` passando `input.value`, pois são strings e a função espera receber números.\n\n```typescript\nconsole.log(sum(input1.value, input2.value));\n```\n\nse tentarmos compilar o código um exception será lançada:\n\n\u003e Para compilar um arquivo TypeScript utilizamos o comando `tsc filename.ts`\n\n```shell\nnpx tsc 1-primeiro-código/somar.ts --watch\n\n[9:58:25 PM] Starting compilation in watch mode...\n\n1-primeiro-código/somar.ts:10:21 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.\n\n10     console.log(sum(input1.value, input2.value));\n                       ~~~~~~~~~~~~\n\n[9:58:27 PM] Found 1 error. Watching for file changes.\n```\n\nPara que o código compile, é necessário converter a string retornada do input para Number:\n\n```javascript\nbutton.addEventListener('click', function() {\n    console.log(sum(Number(input1.value), Number(input2.value)));\n});\n```\n\nApós compilar, o TypeScript gera um arquivo `.js` que deve ser usado na aplicação. No caso, importado na página `index.html`.\n\n## TSconfig\n\nTSconfig é o arquivo de configuração do TypeScript. Com ele é possível definir regras de compilação, outputs etc.\n\nPara gerar o arquivo `tsconfig`:\n\n```shell\ntsc --init\n```\n\nO arquivo é criado no formato `.json` e contém várias regras que podemos adicionar à nossa aplicação.\n\nNa propriedade `outDir` do `tsconfig` é possível explicitar a saída do arquivo `js` que será gerado, por exemplo. E no `index.html` é necessário apontar pra esse arquivo de saída:\n\n`tsconfig.json`:\n\n```json\n...\n\"outDir\": \"./dist\",\n...\n```\n\n`index.html`\n\n```html\n\u003cscript src=\"./dist/somar.js\"\u003e\u003c/script\u003e\n```\n\nNa raiz onde se encontra o `tsconfig`, basta compilar com o comando `tsc` para a pasta `dir` ser gerada com os respectivos arquivos `.js`.\n\n## Recursos da linguagem - Types\n\nA tipagem é uma das features mais importantes do TypeScript. Com ela podemos definir tipos nas variáveis, retorno de funções etc.\n\nVamos ver os principais tipos presentes no TS:\n\n### Any\n\nComo o nome já diz, uma variável de tipo \"qualquer\":\n\n```javascript\nlet value: any;\n\nvalue = 'foo';\nvalue = 10;\nvalue = false;\n```\n\n### Boolean\n\nRecebe `true` ou `false`:\n\n```javascript\nlet isOpened: boolean;\n\nisOpened = false;\nisOpened = 'false'; // Type '\"false\"' is not assignable to type 'boolean'.ts(2322)\n```\n\n### Number\n\nO tipo Number é um pouco diferente do que se vê em outras linguagens. O TypeScript não dispõe de números inteiros, sem sinal ou algo do tipo. Todos os números são definidos como números reais e podem ser representados, inclusive, por binários, hexadecimais etc:\n\n```javascript\nlet total: number;\n\ntotal = 90 + 10;\ntotal = 100.3;\ntotal = 0064;\ntotal = 1100100;\n```\n\n### String\n\nA famosa sequência de caracteres:\n\n```javascript\nlet message: string;\n\nmessage = 'foo';\nmessage = \"foo\";\nmessage = `foo`;\n```\n\n### Array\n\nHá duas formas de se utilizar um array:\n\n```javascript\nlet values: number[];\nvalues = [10, 20, 30];\n\nlet numbers: Array\u003cnumber\u003e;\nnumbers = [10, 20, 30];\n```\n\nA primeira forma seria um \"sugar syntax\", já a segunda utiliza um recurso chamado Generics, muito comum em outras linguagens.\n\n### Tuple\n\nOutro tipo bem comum em outras linguagens são as tuples. É bem semelhante a um array, porém com tamanhos e valores de tipos bem definidos.\n\n```javascript\nlet title: [number, string];\n\ntitle = [1, 'foo'];\n```\n\n### Enum\n\nSão conjuntos ordenados de chaves e valores:\n\n```javascript\nenum Colors {\n    white = '#fff',\n    black = '#000'\n}\n```\n\n### Void\n\nEquivalente a uma função sem retorno:\n\n```javascript\nfunction logger(): void {\n    console.log('hit');\n}\n```\n\n### Null | Undefined\n\nMuito utilizados ao criar um `type`, no exemplo uma variável que recebe uma `string` ou `undefined`:\n\n```javascript\ntype myType = string | undefined;\n\nlet myValue: myType;\n```\n\n### Never\n\nNunca retorna. O código quando lança uma exception, ele nunca vai retornar nada, pois foi interrompido. A função responsável por tratar e até disparar essa expection pode receber o type `never`:\n\n```javascript\nthrow new Error(\"error\");\n\nfunction error(): never {\n    throw new Error(\"error\");\n}\n```\n\n### Object\n\nEstrutura de chave =\u003e valor, muito comum no `JS`:\n\n```javascript\nlet people: object;\n\npeople = {\n    name: 'Maicon',\n};\n```\n\n## Type Inference\n\nAo declararmos uma variável sem tipagem definida, o TypeScript vai utilizar o `type inference`, que define o tipo da variável como o tipo do valor atribuido a ela.\n\n```javascript\nvar text = 'foo'; // string\n```\n\n## Type Aliases e Union\n\nPodemos adotar estratégias para situações em que o tipo do valor pode se sobrepor, por exemplo\numa função onde o primeiro parâmetro pode ser uma `string` ou `number`.\n\nPara esse caso existe o [union](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html), onde os tipos permitidos são separados por `|`:\n\n```javascript\nfunction logDetails(uuid: number | string, item: string) {\n    console.log(`A product with ${uuid} has a title as ${item}`);\n}\n```\n\nTambém existem os [aliases](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases) onde definimos um \"novo\" tipo para o typescript:\n\n```javascript\ntype uuid = number | string;\n\nfunction logDetails(uuid: uuid, item: string) {\n    console.log(`A product with ${uuid} has a title as ${item}`);\n}\n```\n\nDe forma resumida criamos um atalho para uma variável que pode receber mais de um tipo primitivo, um `number` ou uma `string`.\n\nTambém podemos usar os [aliases](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases)\npara receber um valor pré-definido:\n\n```javascript\ntype platform = 'Windows' | 'Linux' | 'MacOS';\n\nfunction logConsole(platform: platform) {\n    console.log(platform);\n}\n\nlogConsole('Windows');\nlogConsole('Ubuntu'); // Argument of type '\"Ubuntu\"' is not assignable to parameter of type 'platform'.ts(2345)\n```\n\n## Classes\n\nO TypeScript pode ser usado tanto com paradigmas como Orientação a Objetos e também funcional.\nPor conta disso, assim como no es6, ele conta com features como [classes](https://www.typescriptlang.org/docs/handbook/classes.html).\n\n```javascript\nclass Employee {\n    public empName: string;\n    protected empCode: number;\n\n    constructor(name: string, code: number){\n        this.empName = name;\n        this.empCode = code;\n    }\n\n    logDetails(): void {\n        console.log(`empName: ${this.empName}, empCode: ${this.empCode}`);\n    }\n}\n\nconst employee = new Employee('maicon', 12);\n\nemployee.logDetails();\n\n// empName: maicon, empCode: 12\n```\n\nClasses também podem ser extendidas, para herdar atributos e métodos:\n\n```javascript\nclass SalesEmployee extends Employee{\n    department: string;\n\n    constructor(name: string, code: number, department: string) {\n        super(name, code);\n\n        this.department = department;\n    }\n\n        employeeDetails(): void {\n        console.log(`\n            empName    : ${this.empName},\n            empCode    : ${this.empCode},\n            departament: ${this.department}`\n        );\n    }\n}\n\nlet emp = new SalesEmployee(\"John Smith\", 123, \"Sales\");\n\nemp.employeeDetails();\n\n// empName: John Smith, empCode: 123, departament: Sales\n```\n\n### Data Modifiers\n\nNa programação orientada a objetos, o conceito de 'Encapsulamento' é usado para tornar os membros da classe públicos ou privados, ou seja, uma classe pode controlar a visibilidade de seus atributos e métodos. Isso é feito usando modificadores de acesso.\n\nExistem quatro tipos principais de modificadores de acesso no TypeScript: `public`, `private`, `protected`, `readonly`.\n\n#### Public\n\nPor padrão, todos os membros de uma classe no TypeScript são públicos. Todos os membros públicos podem ser acessados ​​em qualquer lugar, sem restrições.\n\n```javascript\nclass Employee {\n    public empCode: string;\n    empName: string;\n}\n\nlet emp = new Employee();\n\nemp.empCode = 123;\nemp.empName = \"Swati\";\n```\n\n#### Private\n\nO modificador de acesso privado garante que os membros da classe sejam visíveis apenas para essa classe e não sejam acessíveis fora da classe que o contém.\n\n```javascript\nclass Employee {\n    private empCode: number;\n    empName: string;\n}\n\nlet emp = new Employee();\n\nemp.empCode = 123; // Compiler Error\nemp.empName = \"Swati\"; // OK\n```\n\n#### Protected\n\nO modificador de acesso protegido é semelhante ao modificador de acesso privado, exceto que os membros protegidos podem ser acessados ​​usando suas classes derivadas.\n\n```javascript\nclass Employee {\n    public empName: string;\n    protected empCode: number;\n\n    constructor(name: string, code: number){\n        this.empName = name;\n        this.empCode = code;\n    }\n}\n\nclass SalesEmployee extends Employee{\n    private department: string;\n\n    constructor(name: string, code: number, department: string) {\n        super(name, code);\n        this.department = department;\n    }\n}\n\nlet emp = new SalesEmployee(\"John Smith\", 123, \"Sales\");\n\nemp.empCode; //Compiler Error\n```\n\n#### Readonly\n\nO modificador de acesso para leitura. Permite que um atributo seja acessível de fora da classe, mas não alterado:\n\n```javascript\nclass Employee {\n    readonly empCode: number;\n    empName: string;\n}\n\nlet emp = new Employee();\n\nemp.empCode = 123; // Compiler Error\n```\n\n## TypeScript Accessor\n\nO TypeScript suporta getters/setters como uma maneira de interceptar acessos a um atributo de um objeto. Isso fornece uma maneira de ter um controle mais refinado sobre como um atributo é acessado em cada objeto.\n\nVamos converter uma classe simples para usar get e set. Primeiro, vamos começar com um exemplo sem utilizar `acessors`:\n\n```javascript\nclass Employee {\n    fullName: string;\n}\n\nlet employee = new Employee();\n\nemployee.fullName = \"Bob Smith\";\n\nif (employee.fullName) {\n    console.log(employee.fullName);\n}\n```\n\nMudar ou recuperar atributos de uma classe de forma explícita pode ser conveniente, mas isso torna o código frágil.\n\nCom getters e setters podemos definir regras ao setar um nome, e também preservar os atributos da classe fornecendo-o através de um getter:\n\nNo exemplo a seguir o atributo `_fullName` é privado, e só pode ser definido seguindo uma regra de `maxLenght`:\n\n```javascript\nconst fullNameMaxLength = 10;\n\nclass User {\n    private _fullName: string;\n\n    constructor(name: string) {\n        this._fullName = name;\n    }\n\n    get fullName(): string {\n        return this._fullName;\n    }\n\n    set fullName(newName: string) {\n        if (newName \u0026\u0026 newName.length \u003e fullNameMaxLength) {\n            throw new Error(\"fullName has a max length of \" + fullNameMaxLength);\n        }\n\n        this._fullName = newName;\n    }\n}\n\nlet user = new User('Denis Chambers');\n\nconsole.log('constructor', user.fullName)\n\nuser.fullName = \"Bob Smith\";\n\nconsole.log('setter', user.fullName);\n```\n\nUm detalhe é que getters e setters não são chamados como um método ou função utilizando parênteses, mas apenas como atributo\ndo objeto:\n\n```javascript\nuser.fullName = 'Maicon Silva'; // Setter\nuser.fullName; // Getter\n```\n\n## Classes abstratas\n\nClasses abstratas são classes base das quais outras classes podem ser derivadas. Elas não podem ser instanciadas diretamente.\n\n```javascript\nabstract class Animal {\n    abstract makeSound(): void;\n\n    move(): void {\n        console.log(\"roaming the earth...\");\n    }\n}\n```\n\nSão utilizadas como modelos para outras classes, para serem extendidas e então instanciadas.\n\n## Interfaces\n\n[Interaces](https://www.typescriptlang.org/docs/handbook/interfaces.html) descreve o formato que um objeto deve ter:\n\n```javascript\ninterface LabeledValue {\n    size: number;\n    label: string;\n    tags: string[];\n    getTag: (tag: string) =\u003e string;\n}\n\nfunction printLabel(labeledObj: LabeledValue) {\n    console.log(labeledObj.label);\n}\n\nlet myObj: LabeledValue = {\n    size: 10,\n    label: \"Size 10 Object\",\n    tags: ['number', 'string', 'array'],\n    getTag: (label) =\u003e label,\n};\n\nprintLabel(myObj);\n```\n\nAs `interfaces` trabalham com todos os tipos primitivos e também aceitam `aliases` ou até mesmo outra `interface`:\n\n```javascript\ninterface User {\n    name: string;\n    age?: number;\n}\n\ninterface LabeledValue {\n    id: string | number;\n    user: User;\n}\n\nlet myObj: LabeledValue = {\n    id: 10,\n    user: {\n        name: 'Maicon'\n    },\n}\n```\n\nPara declararmos uma atributo na `interace` que é opcional, interrogação `?` deve ser adicionado na propriedade opcional:\n\n```javascript\ninterface LabeledValue {\n    id?: string | number;\n}\n```\n\nCaso contrário o objeto criado deve possuir todas as propriedades presente na `interface` para não ocorrer erro de compilação.\n\n### Readonly property\n\nUma `interface` pode receber o modificador de acesso para propriedades que não podem ser alteradas após a criação do objeto. Para isso a propriedade em questão deve ser precedida de `readonly` e o objeto deve receber a interface como tipagem:\n\n```javascript\ninterface User {\n    readonly id: number;\n    name: string;\n}\n\nconst user: User = {\n    id: 1,\n    name: 'Maicon'\n}\n\nuser.id = 12; // Compile Error\nuser.name = 'Maicon Silva'; // OK\n```\n\n### Extends interface\n\nInterfaces podem ser extendidas assim como classes, dessa maneira a nova interface criada recebe os atributos da \"interface mãe\", mais os seus:\n\n```javascript\ninterface User {\n    readonly id: number;\n    name: string;\n}\n\ninterface UserAddress extends User {\n    zipcode: string;\n}\n\nconst address: UserAddress = {\n    id: 1,\n    name: 'Maicon',\n    zipcode: '05164110'\n}\n```\n\n### Implementando a interface em uma classe\n\nPodemos também implementar uma classe que utiliza uma interface como base:\n\n```javascript\ninterface User {\n    readonly id: number;\n    name: string;\n}\n\nclass CreateUser implements User {\n    id: number;\n    name: string;\n\n    constructor(id, name) {\n        this.id = id;\n        this.name = name;\n    }\n}\n\nconst user = new CreateUser(10, 'Maicon Silva');\n```\n\n## Generics\n\nUma parte importante na engenharia de software é a construção de componenets que não apenas possuem um\nescopo bem definido e consistente, mas que também são reutilizaveis. Esses são os [generics](https://www.typescriptlang.org/docs/handbook/generics.html).\n\nVamo criar uma função que é reposável por atribuir e retornar o estado de uma variável:\n\n```javascript\nfunction useState() {\n    let state: number;\n\n    function getState() {\n        return state;\n    }\n\n    function setState(newState: number) {\n        state = newState;\n    }\n\n    return {\n        getState,\n        setState,\n    };\n}\n\nconst newState = useState();\n\nnewState.setState(123);\n\nconsole.log(newState.getState()); // 123\n```\n\nNesse cenário, passar uma string ou qualquer outro tipo de dado para `setState` vai gerar um erro de compilação, pois a função `setState` espera receber um número.\n\nUma forma de contornar isso seria utilizar o `union`:\n\n```javascript\n...\n\nlet state: number | string;\n\nfunction setState(newState: number | string) {\n    state = newState;\n}\n\n...\n\nnewState.setState(123); // OK\nnewState.setState('string'); // OK\n```\n\nNesse momento entra o `generic`. Através do `generic` a variável pode receber seu tipo na primera vez que `useState` foi chamado, e não ser alterado posteriormente:\n\n```javascript\nnewState.setState(123); // Agora o state é um número\nnewState.setState('string'); // Erro\n```\n\nEmbora o uso `any` ou `union` possa ser genérico, ele pode nos privar de saber exatamente o valor que está entrando na função e também o que essa função irá retornar exatamente.\n\nNesse caso, precisamos de uma maneira de capturar o tipo do argumento de forma que também possamos usá-lo para indicar o que está sendo retornado. No próximo exemplo, vamor usar uma variável especial, um tipo de variável que funciona em tipos e não em valores.\n\n```javascript\n// S = state\n// T = Type\n// K = key\n// V = value\n// E = element\n\nfunction useState\u003cS\u003e() {\n    let state: S;\n\n    function getState() {\n        return state;\n    }\n\n    function setState(newState: S) {\n        state = newState;\n    }\n\n    return {\n        getState,\n        setState,\n    };\n}\n```\n\nIsso faz com que o tipo da vairável seja definido no momento em que a função é chamada a primeira vez, no nosso caso na criação do `newState`.\n\nSe o tipo não for definido `unknown` será retornado:\n\n```javascript\nfunction useState\u003cunknown\u003e(): {\n    getState: () =\u003e unknown;\n    setState: (newState: unknown) =\u003e void;\n}\n```\n\nPara definirmos a tipagem do generic, basta adicionar `\u003ctype\u003e` na criação de `useState`:\n\n```javascript\nconst newState = useState\u003cstring\u003e();\n\nnewState.setState('Agora é uma string'); // OK, foi criado como uma \u003cstring\u003e\nconsole.log(newState.getState());\n\nnewState.setState(123); // Erro\nconsole.log(newState.getState());\n```\n\nDessa forma nosso código bloqueia a entrada de qualquer dado que não seja uma string na função, mas isso\nfaz com que qualquer tipagem possa ser atribuida como `generic` de `useState` na sua criação:\n\n```javascript\nconst newState = useState\u003cboolean | number[]\u003e();\n\nnewState.setState([123, 456]); // OK\nconsole.log(newState.getState());\n\nnewState.setState(false); // OK\nconsole.log(newState.getState());\n\nnewState.setState('Agora é uma string'); // Error\nconsole.log(newState.getState());\n```\n\nÉ possível extender os tipos que o `generic` de `useState` pode aceitar para controlar sua inicialização:\n\n```javascript\nfunction useState\u003cS extends string | number\u003e() {\n    let state: S;\n\n    function getState() {\n        return state;\n    }\n\n    function setState(newState: S) {\n        state = newState;\n    }\n\n    return {\n        getState,\n        setState,\n    };\n}\n\nconst newState = useState\u003cboolean | number[]\u003e(); // Erro\n```\n\n### Default generic type\n\nTambém podemos atribuir um valor padrão para o `generic` utilizando o operador `=`:\n\n```javascript\nfunction useState\u003cS extends string | number = string\u003e() {\n    let state: S;\n\n    function getState() {\n        return state;\n    }\n\n    function setState(newState: S) {\n        state = newState;\n    }\n\n    return {\n        getState,\n        setState,\n    };\n}\n```\n\nIsso faz com que se `useState` for chamado sem a definição do `generic`, o tipo atribuido será `string`:\n\n```javascript\nconst newState = useState(); // string\n\nnewState.setState('Agora é uma string');\nconsole.log(newState.getState());\n\nnewState.setState(123); // Erro\nconsole.log(newState.getState());\n```\n\n## Type Utilities\n\nO TypeScript fornece vários [type utilities](https://www.typescriptlang.org/docs/handbook/utility-types.html) para facilitar transformações de tipos comuns. Esses utilitários estão disponíveis globalmente.\n\n```javascript\ninterface Todo {\n    title: string;\n    description: string;\n    completed: boolean;\n}\n\nconst todo: Todo = {\n    title: 'Delete inactive users',\n    description: 'Remove all inactive users',\n    completed: false,\n};\n\nconsole.log(todo); // { ..., completed: false }\n\ntodo.completed = true; // OK\n\nconsole.log(todo); // { ..., completed: true }\n```\n\nAlterar propriedades de objetos de forma direta pode acarretar side effects, quebra de contratos etc. Uma forma de previnir essa operação seria o `Readonly\u003cT\u003e` type utilitie:\n\n```javascript\ninterface Todo {\n    title: string;\n    description: string;\n    completed: boolean;\n}\n\nconst todo: Readonly\u003cTodo\u003e = {\n    title: 'Delete inactive users',\n    description: 'Remove all inactive users',\n    completed: false,\n};\n\nconsole.log(todo);\n\ntodo.completed = true; // Error\n\nconsole.log(todo);\n```\n\nUma forma de alterar esse objeto seria uma função que recebe o objeto e os dados que devem ser alterados, e retorna esses\nvalores atualizados. Para isso temos o `Partial\u003cT\u003e`, que recebe propriedades do tipo, porém de forma opcional:\n\n```javascript\ninterface Todo {\n    title: string;\n    description: string;\n}\n\nfunction updateTodo(todo: Todo, fieldsToUpdate: Partial\u003cTodo\u003e) {\n    return { ...todo, ...fieldsToUpdate };\n}\n\nconst todo1 = {\n    title: 'organize desk',\n    description: 'clear clutter',\n};\n\nconst todo2 = updateTodo(todo1, {\n    description: 'throw out trash',\n});\n```\n\nTambém podemos criar um novo tipo \"pegando propriedades\" de um tipo já existente com o `pick`:\n\n```javascript\ninterface Todo {\n    title: string;\n    description: string;\n    completed: boolean;\n}\n\ntype TodoPreview = Pick\u003cTodo, 'title' | 'completed'\u003e;\n\nconst todo: TodoPreview = {\n    title: 'Clean room',\n    completed: false,\n};\n```\n\nUma outra forma de conseguir o mesmo resultado seria usar o `Omit`:\n\n```javascript\ninterface Todo {\n    title: string;\n    description: string;\n    completed: boolean;\n}\n\ntype TodoPreview = Omit\u003cTodo, 'description'\u003e;\n\nconst todo: TodoPreview = {\n    title: 'Clean room',\n    completed: false,\n};\n```\n\nEle funciona de forma contraria ao `Pick`, recebendo apenas as propriedades que devem ser omitidas, no caso `description`. Assim `TodoPreview` é construido com `title` e `completed`.\n\nExistem alguns outros type utilities que podemos usar, vale a pena conferir na [doc](https://www.typescriptlang.org/docs/handbook/utility-types.html).\n\n## Decorators\n\nOs [decorator](https://www.typescriptlang.org/docs/handbook/decorators.html) são um recurso que pode ser usado para extender funcionalidades de classes, métodos, acessador, propriedade ou parâmetro. Utilizam `@Expression`, onde `expression` deve avaliar uma função que será chamada em tempo de execução com informações sobre a declaração decorada.\n\nAtualmente os decorators é uma proposta de [estágio 2](https://github.com/tc39/proposal-decorators) para o TypeScript.\n\n\u003e Decoradores são um recurso experimental que pode mudar em versões futuras.\n\nPara habilitar o suporte experimental dos decorators, é necessário uma configuração no `tsconfig.json`:\n\n```javascript\n...\n\"experimentalDecorators\": true,\n...\n```\n\n### Criando um decorator\n\nO decorador é uma função que recebe `target`, senndo `target` a instância da classe, como um parâmetro default:\n\n```javascript\nfunction sealed(target) {\n    console.log(target);\n}\n\n@sealed\nclass Foo {}\n```\n\n### Factory decorator\n\nSe quisermos personalizar como um decorador é aplicado a uma declaração, podemos escrever uma fábrica de decoradores. Uma Decorator Factory é simplesmente uma função que retorna a expressão que será chamada pelo decorador em tempo de execução.\n\nPodemos escrever uma fábrica de decoradores da seguinte maneira:\n\n```javascript\nfunction logger(prefix: string) {\n    return (target) =\u003e {\n        console.log(`${target} - ${prefix}`);\n    }\n}\n\n\n@logger('isSealed')\nclass Foo { }\n```\n\n### Class decorator\n\nComo exemplo, vamos criar uma classe `API` que recebe um `decorator` para setar sua versão.\n\nO que esse `decorator` de class faz é retornar um construtor de classe que extende por padrão a classe `target`:\n\n```javascript\nfunction setAPIVersion(apiVersion: string) {\n    return (constructor) =\u003e {\n        return class extends constructor {\n            version = apiVersion;\n        }\n    }\n}\n\n@setAPIVersion('1.0.8')\nclass API { }\n\nconsole.log(new API()); // class_1 { version: '1.0.8' }\n```\n\n### Property decorator\n\nUm case comum é precisarmos validar uma propriedade de uma classe no momento em que ela é instânciada ou em que o dado é alterado. Nesse cenário, um `property decorator` é uma solução.\n\nImagina a classe `Person` que precisa receber a idade da pessoa, porém essa pessoa precisa ser maior de idade, ou no nosso caso, ter mais que 18 anos:\n\n```javascript\nfunction minPersonAge(minAge: number) {\n    return (target: any, key: string) =\u003e {\n        let val = target[key];\n\n        const getter = () =\u003e val;\n\n        const setter = (value: number) =\u003e {\n            if (value \u003c 18) {\n                throw new Error('Age must be over 18');\n            }\n\n            val = value;\n        };\n\n        Object.defineProperty(target, key, {\n            get: getter,\n            set: setter,\n        });\n    };\n}\n\nclass Person {\n    // Precisa ser maior que 18\n    @minPersonAge(18)\n    age: number;\n\n    constructor(a: number) {\n        this.age = a;\n    }\n}\n\nconsole.log(new Person(17)); // Error\nconsole.log(new Person(18)); // Person {}\n```\n\n### Method decorator\n\n### Parameter decorator\n\n### Acessor decorator\n\n# Conclusão\n\nO uso do TypeScript trás uma série de benefícios ao JavaScript. A fluência na linguagem só vai acontecer a partir do momento que você começar a utiliza-lo, e ver como é bom ter um controle maior sobre os dados que entram e saem do seu sistema. Como toda tecnologia é necessário praticar e aplicar.\n\nSe você ja programa em JavaScript, a curva de adaptação é pequena, e é algo que vale a pena encarar.\n\nPara concluir, os tópicos que abordamos no post foram:\n\n- Por que usar TypeScript?;\n- Primeiro código, compilação;\n- TSConfig;\n- Recursos da linguagem - Types;\n- Type Inference;\n- Type Aliases e Union;\n- Classes;\n- TypeScript Accessors;\n- Classes abstratas;\n- Interfaces;\n- Generics;\n- Type Utilities;\n- Decorators.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaiconwte%2Fstarting-typescript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaiconwte%2Fstarting-typescript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaiconwte%2Fstarting-typescript/lists"}