├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── src
├── app.ts
├── desafios
│ ├── desafio1.js
│ ├── desafio2.js
│ ├── desafio3.js
│ └── desafio4.js
├── exemplos
│ ├── any-vs-unknown-e-never.ts
│ ├── any.ts
│ ├── basico.ts
│ ├── combinando.ts
│ ├── enum.ts
│ ├── exemplo-validacao.js
│ ├── functions.ts
│ └── objetos.ts
└── respostas
│ ├── desafio1.ts
│ ├── desafio2.ts
│ └── desafio3.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | app.js
3 | **/*.js
4 | **/*.js.map
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Aula de Typescript da Take na plataforma DIO
2 |
3 | *Bem vindo!!*
4 |
5 | O objetivo desse repositório é mostrar exemplos e desafios de typescript que vão dar uma noção geral suficiente da ferramenta para que ela seja usada no dia a dia do desenvolvedor.
6 |
7 | Para quem é esse repositório:
8 | * Pessoas que tem vontade de aprender javascript aplicando boas práticas desde o início
9 | * Pessoas que já usam javascript e querem desaprender hábitos negativos da linguagem
10 | * Quem já teve dor de cabeça com javascript e tem um trauma a ser curado
11 |
12 | ## O que é o Typescript
13 | É um superset do typescript que trás tipagem estática para a linguagem, além de outras features, com o propósito de melhorar a qualidade do código escrito e a sua usabilidade. Como é um superset o código compilado e usado em produção ainda é javascript, porém é um JS mais resiliente e turbinado graças ao uso de TS durante o desenvolvimento.
14 |
15 | ## Do que você vai precisar
16 | Ferramentas necessárias:
17 | * Do Node instalado na sua máquina
18 | * Instalar o typescript usando o npm (npm install -g typescript)
19 | * É interessante que ele seja instalado de forma global, para que o usuário possa usar a biblioteca a qualquer momento e em qualquer projeto para fazer testes rápidos com o TS.
20 | * De uma IDE como o visual studio code
21 |
22 | Requisitos técnicos:
23 | * Lógica de programação
24 | * Mas é melhor ainda se tiver um conhecimento básico de javascript
25 |
26 | ## Sobre a estrutura de commits
27 | Os commits foram feitos de tal forma que o usuário pode ler commit a commit em ordem de publicação e acompanhar gradualmente a criação do repositório e a lógica aplicada. É recomendado que o primeiro estudo seja feito dessa forma. Pequenos erros nos comentários ou de gramática podem ser encontrados no caminho (consequências do programador que estuda de madrugada), mas eles já foram devidamente corrigidos na última versão da main.
28 |
29 | ## Estrutura do repositório
30 | * *src*
31 | * Contém arquivos com exemplos de uso de TS e JS comentados para facilitar o entendimento da ferramenta
32 | * *desafios*
33 | * Contém vários arquivos JS que podem ser refatorados para solidificar o conhecimento adquirido na aula
34 | * *index.html*
35 | * É onde está a chamada para o arquivo app.js e pode ser manipulado a vontade para testarem seus scripts
36 | * *tsconfig.json*
37 | * O coração do TS que configura suas funcionalidades.
38 | * *package.json*
39 | * Nesse arquivo foram colocados alguns scripts com o propósito de facilitar a vida de quem usar esse repositório
40 | * start
41 | * Inicia o *lite-server*, que vai escutar modificações no index.html e em seus arquivos importados. É útil caso queira fazer testes no browser. A porta disposta normalmente é a *localhost:3000*
42 | * watch
43 | * Roda o *tsc --watch* com o propósito de compilar constantemente qualquer coisa que for editada nos arquivos TS para sua contraparte em JS. Esse comando evita que *tsc* tenha que ser digitado constantemente para fazer a compilação.
44 |
45 | ## Sobre como testar
46 | * Teste mão livre
47 | * Faça suas alterações em src/app.ts
48 | * Rode *tsc* ou *npm watch* para compilar elas para o arquivo dist/app.js
49 | * Caso queira fazer um teste interagindo com o DOM, altere o index.html
50 | * Rode o npm start e acesse o localhost:3000
51 | * Testar algum dos arquivos da pasta de exemplos ou desafios
52 | * Copie e cole o conteúdo para o arquivo src/app.ts ou altere o caminho do atributo src da tag script no index.html
53 | * ex : *src=dist/app.js* -> *src=dist/exemplos/any.js*
54 | * Rode *tsc* ou *npm watch* para compilar elas para o arquivo dist/app.js
55 | * Caso queira fazer um teste interagindo com o DOM, altere o index.html
56 | * Rode o npm start e acesse o localhost:3000
57 | Caso queira fazer testes usando html é só alterar o index.html.
58 |
59 | ## Sobre o tsconfig.json
60 | * Algumas configurações e funcionalidades legais são:
61 | 1. Opções básicas:
62 | * target
63 | * Define para qual versão do ECMAScript o typescript vai ser convertido
64 | * lib
65 | * Define quais bibliotecas vão vir por default com o TS. Isso é bacana caso o TS esteja sendo usado no backend e a iteração com o DOM não é necessária. Como teste, tentem remover as bibliotecas do DOM e olhem seu código enchendo de erros porque não sabe o que é um document
66 | * sourceMap
67 | * Cria arquivos .map.js que geram uma cópia do seu arquivo TS no source do browser (aquele do inspect). Podem ser debugados via breakpoint direto no browser e são uma excelente ajuda, já que o código compilado de JS é menos legível que o TS.
68 | * outDir
69 | * Pasta para onde seus arquivos JS serão enviados
70 | * rootDir
71 | * Pasta de onde seus arquivos TS serão coletados. Pode ser necessário inserir a opção include fora do *compilerOptions* com a pasta *src* inclusa
72 | 2. Opções de checagem de tipo:
73 | * strict
74 | * Marca todas opções de checagem de tipo como verdadeiras. Ideal caso seja a intenção do usuário ter o código mais consistente possível
75 | * noImplicitAny
76 | * Levanta erro caso variáveis não estejam tipadas. Caso essa seja a intenção, um "any" tem que ser explicitamente tipado
77 | * strictNullChecks
78 | * Pode levantar erro caso uma variável em uso seja potencialmente nula.
79 | * Ex: um botão que foi buscado usando um getElementById que não necessariamente vai encontrar um elemento é usado para escutar um evento.
80 | 3. Outras opções
81 | * noUnusedLocals
82 | * Levanta erro sempre que uma variável local não está sendo utilizada, como um let dentro de uma função
83 | * nuUnusedParameters
84 | * Mesmo caso de noUnusedLocals, mas para parâmetros de função
85 | * noImplicitReturns
86 | * Levanta um erro caso uma função tenha caminhos que retornam valor e outros que não retornam
87 | 4. Existem outras regras e explicações mais elaboradas na documentação oficial (https://www.typescriptlang.org/tsconfig)
88 |
89 | ## Sobre colaboração
90 | Sinta-se livre para abrir pull requests com melhorias para ajudar quem quiser aprender mais sobre Typescript. Também podem tirar dúvidas comigo via comentário.
91 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
31 | */
--------------------------------------------------------------------------------
/src/desafios/desafio4.js:
--------------------------------------------------------------------------------
1 | // Um desenvolvedor tentou criar um projeto que consome a base de dados de filme do TMDB para criar um organizador de filmes, mas desistiu
2 | // pois considerou o seu código inviável. Você consegue usar typescript para organizar esse código e a partir daí aprimorar o que foi feito?
3 |
4 | // A ideia dessa atividade é criar um aplicativo que:
5 | // - Busca filmes
6 | // - Apresenta uma lista com os resultados pesquisados
7 | // - Permite a criação de listas de filmes e a posterior adição de filmes nela
8 |
9 | // Todas as requisições necessárias para as atividades acima já estão prontas, mas a implementação delas ficou pela metade (não vou dar tudo de graça).
10 | // Atenção para o listener do botão login-button que devolve o sessionID do usuário
11 | // É necessário fazer um cadastro no https://www.themoviedb.org/ e seguir a documentação do site para entender como gera uma API key https://developers.themoviedb.org/3/getting-started/introduction
12 |
13 | var apiKey = '3f301be7381a03ad8d352314dcc3ec1d';
14 | let apiKey;
15 | let requestToken;
16 | let username;
17 | let password;
18 | let sessionId;
19 | let listId = '7101979';
20 |
21 | let loginButton = document.getElementById('login-button');
22 | let searchButton = document.getElementById('search-button');
23 | let searchContainer = document.getElementById('search-container');
24 |
25 | loginButton.addEventListener('click', async () => {
26 | await criarRequestToken();
27 | await logar();
28 | await criarSessao();
29 | })
30 |
31 | searchButton.addEventListener('click', async () => {
32 | let lista = document.getElementById("lista");
33 | if (lista) {
34 | lista.outerHTML = "";
35 | }
36 | let query = document.getElementById('search').value;
37 | let listaDeFilmes = await procurarFilme(query);
38 | let ul = document.createElement('ul');
39 | ul.id = "lista"
40 | for (const item of listaDeFilmes.results) {
41 | let li = document.createElement('li');
42 | li.appendChild(document.createTextNode(item.original_title))
43 | ul.appendChild(li)
44 | }
45 | console.log(listaDeFilmes);
46 | searchContainer.appendChild(ul);
47 | })
48 |
49 | function preencherSenha() {
50 | password = document.getElementById('senha').value;
51 | validateLoginButton();
52 | }
53 |
54 | function preencherLogin() {
55 | username = document.getElementById('login').value;
56 | validateLoginButton();
57 | }
58 |
59 | function preencherApi() {
60 | apiKey = document.getElementById('api-key').value;
61 | validateLoginButton();
62 | }
63 |
64 | function validateLoginButton() {
65 | if (password && username && apiKey) {
66 | loginButton.disabled = false;
67 | } else {
68 | loginButton.disabled = true;
69 | }
70 | }
71 |
72 | class HttpClient {
73 | static async get({url, method, body = null}) {
74 | return new Promise((resolve, reject) => {
75 | let request = new XMLHttpRequest();
76 | request.open(method, url, true);
77 |
78 | request.onload = () => {
79 | if (request.status >= 200 && request.status < 300) {
80 | resolve(JSON.parse(request.responseText));
81 | } else {
82 | reject({
83 | status: request.status,
84 | statusText: request.statusText
85 | })
86 | }
87 | }
88 | request.onerror = () => {
89 | reject({
90 | status: request.status,
91 | statusText: request.statusText
92 | })
93 | }
94 |
95 | if (body) {
96 | request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
97 | body = JSON.stringify(body);
98 | }
99 | request.send(body);
100 | })
101 | }
102 | }
103 |
104 | async function procurarFilme(query) {
105 | query = encodeURI(query)
106 | console.log(query)
107 | let result = await HttpClient.get({
108 | url: `https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&query=${query}`,
109 | method: "GET"
110 | })
111 | return result
112 | }
113 |
114 | async function adicionarFilme(filmeId) {
115 | let result = await HttpClient.get({
116 | url: `https://api.themoviedb.org/3/movie/${filmeId}?api_key=${apiKey}&language=en-US`,
117 | method: "GET"
118 | })
119 | console.log(result);
120 | }
121 |
122 | async function criarRequestToken () {
123 | let result = await HttpClient.get({
124 | url: `https://api.themoviedb.org/3/authentication/token/new?api_key=${apiKey}`,
125 | method: "GET"
126 | })
127 | requestToken = result.request_token
128 | }
129 |
130 | async function logar() {
131 | await HttpClient.get({
132 | url: `https://api.themoviedb.org/3/authentication/token/validate_with_login?api_key=${apiKey}`,
133 | method: "POST",
134 | body: {
135 | username: `${username}`,
136 | password: `${password}`,
137 | request_token: `${requestToken}`
138 | }
139 | })
140 | }
141 |
142 | async function criarSessao() {
143 | let result = await HttpClient.get({
144 | url: `https://api.themoviedb.org/3/authentication/session/new?api_key=${apiKey}&request_token=${requestToken}`,
145 | method: "GET"
146 | })
147 | sessionId = result.session_id;
148 | }
149 |
150 | async function criarLista(nomeDaLista, descricao) {
151 | let result = await HttpClient.get({
152 | url: `https://api.themoviedb.org/3/list?api_key=${apiKey}&session_id=${sessionId}`,
153 | method: "POST",
154 | body: {
155 | name: nomeDaLista,
156 | description: descricao,
157 | language: "pt-br"
158 | }
159 | })
160 | console.log(result);
161 | }
162 |
163 | async function adicionarFilmeNaLista(filmeId, listaId) {
164 | let result = await HttpClient.get({
165 | url: `https://api.themoviedb.org/3/list/${listaId}/add_item?api_key=${apiKey}&session_id=${sessionId}`,
166 | method: "POST",
167 | body: {
168 | media_id: filmeId
169 | }
170 | })
171 | console.log(result);
172 | }
173 |
174 | async function pegarLista() {
175 | let result = await HttpClient.get({
176 | url: `https://api.themoviedb.org/3/list/${listId}?api_key=${apiKey}`,
177 | method: "GET"
178 | })
179 | console.log(result);
180 | }
181 |
182 | {/*
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
*/}
--------------------------------------------------------------------------------
/src/exemplos/any-vs-unknown-e-never.ts:
--------------------------------------------------------------------------------
1 | let valor: unknown; // unknown é um tipo que pode receber qualquer valor
2 | valor = 5;
3 | valor = 'Max';
4 | let nome: string;
5 |
6 | // nome = valor; Isso não vai funcionar. O tipo unknown não pode ser arbitrariamente atribuído
7 | if (typeof valor === 'string') {
8 | nome = valor; // Isso funciona. Esse tipo só pode ser atribuido se uma validação for feita
9 | }
10 |
11 | let valorAny: any; // Como já foi visto, o any também recebe qualquer valor
12 | valorAny = true;
13 | valorAny = 10
14 | nome = valorAny; // O perigo é que o any pode ser atribuído a qualquer variável tipada sem que seu tipo seja verificado
15 |
16 | // Não é uma prática ruim usar unknown, já que ele força uma validação de tipos. Diferente do any, que como já vimos pode ser usado sem se preocupar com tipage.
17 |
18 | function geradorDeErro(mensagem: string, codigoDeErro: number): never { // never quer dizer que o script pode ser interrompido ou nunca chegar a um fim
19 | throw {message: mensagem, errorCode: codigoDeErro }; // Nesse caso ele foi interrompido
20 | }
21 |
22 | geradorDeErro('Um erro ocorreu!', 500); // O mesmo tipo poderia ser usado se fosse usado um while loop que nunca é finalizado
--------------------------------------------------------------------------------
/src/exemplos/any.ts:
--------------------------------------------------------------------------------
1 | // O any é uma notação que diz que a propriedade pode ter qualquer tipo
2 | let cpf: any;
3 | // Aqui ela recebe uma string
4 | cpf = '01620445000';
5 | // Aqui recebe um boolean
6 | cpf = true;
7 | // E agora um número
8 | cpf = 10;
9 | // O uso de any faz com que typescript trate suas variáveis como JS
10 |
11 | // Essa função abaixo espera uma string
12 | function apresentarCPF(cpf: string) {
13 | console.log(cpf)
14 | }
15 |
16 | // E aqui passamos a variável cpf que contém um number, mas como ela é um any, o TS não reclama porque ela pode conter qualquer atributo, inclusive uma string
17 | apresentarCPF(cpf);
18 | /**
19 | Usar any tira poder do typescript e pode criar incoerências no seu projeto
20 | O any é comumente usado quando um objeto desconhecido é manipulado, ou quando uma refatoração de JS para TS é aplicada rapidamente sem tipar os objetos utilizados
21 | É uma má prática que reduz a velocidade dos times no longo prazo e foge do propósito do typescript
22 | Com o uso do ESLint é possível configurar seu projeto para não permitir o uso explícito de any
23 | */
--------------------------------------------------------------------------------
/src/exemplos/basico.ts:
--------------------------------------------------------------------------------
1 | const button = document.getElementById('button');
2 | const input1 = document.getElementById('input1') as HTMLInputElement;
3 | const input2 = document.getElementById('input2') as HTMLInputElement;
4 |
5 | /**
6 | * Exemplo de função com parâmetros tipados
7 | */
8 | function somaValidaComPrint(numero1: number, numero2: number, printarResultado: boolean, frase: string) {
9 | const resultado = numero1 + numero2;
10 | if (printarResultado) {
11 | console.log(frase + resultado);
12 | }
13 | return resultado;
14 | }
15 |
16 | // A variável abaixo tem seu tipo inferido pelo valor inicial
17 | let printarResultado = true;
18 | // já nesse caso estamos dizendo explicitamente qual é o seu tipo
19 | let frase: string;
20 | // E só depois iniciamos ela com um valor
21 | frase = "O número é ";
22 |
23 | // Como a busca pelo button na linha 1 pode trazer um null (já que esse id pode não estar presente no index.html), é importante confirmar se ele tem um valor
24 | if (button) {
25 | button.addEventListener('click', () => {
26 | console.log(somaValidaComPrint(Number(input1.value), Number(input2.value), printarResultado, frase));
27 | });
28 | }
--------------------------------------------------------------------------------
/src/exemplos/combinando.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Quando tipamos podemos passar mais de um tipo, como no caso abaixo em que cada parâmetro contém o tipo input, que é igual aos tipos number ou string
3 | * No exemplo abaixo também ocorre um tratamento interno na função para que ela lide com os diferentes tipos de cada parâmetro
4 | */
5 |
6 | // Também é possível criar tipos! E combinar tipos com esses tipos!
7 | type input = number | string;
8 |
9 | function juntar(input1: input, input2: input) {
10 | let resultado: input;
11 | if (typeof input1 === 'string' || typeof input2 === 'string') {
12 | resultado = input1.toString() + input2.toString();
13 | } else {
14 | resultado = input1 + input2
15 | }
16 | return resultado;
17 | }
18 |
19 | // E aqui temos dois exemplos de uma chamada para essa função, um com strings e um com números
20 | console.log(juntar('bom ', 'dia'));
21 | console.log(juntar(1, 2));
22 |
--------------------------------------------------------------------------------
/src/exemplos/enum.ts:
--------------------------------------------------------------------------------
1 | const sarah = {
2 | name: 'Sarah',
3 | idade: 26,
4 | casado: true,
5 | trabalho: 'Engenheira' // Nesse campo é dito que a sarah trabalha como 'Engenheira'
6 | }
7 |
8 | const maria = {
9 | name: 'Maria',
10 | idade: 23,
11 | casado: false,
12 | trabalho: 'engenheira' // E aqui é dito que maria trabalha como 'engenheira'.
13 | }
14 |
15 | // Isso está correto? Existe diferença entre 'Engenheira' e 'engenheira'? Acredito que não. Isso deve ter sido um erro cometido em desenvolvimento.
16 |
17 | // Para resolver isso vamos usar a feature Enum do TypeScript para criar o enum Profissao
18 | enum Profissao {
19 | Professor,
20 | Engenheiro,
21 | Pintor,
22 | Porteiro
23 | }
24 |
25 | // E para garantir que o enum vai ser usado corretamente, vamos criar um tipo Pessoa também
26 | type Pessoa = {
27 | name: string,
28 | idade: number,
29 | casado: boolean,
30 | trabalho: Profissao // Aqui inserimos o enum como um tipo
31 | }
32 |
33 | const gabriel: Pessoa = {
34 | name: 'Gabriel',
35 | idade: 26,
36 | casado: false,
37 | trabalho: Profissao.Engenheiro // E aqui usamos ele para definir de forma padronizada a profissão de cada objeto do tipo Pessoa
38 | }
39 |
40 | const mario: Pessoa = {
41 | name: 'Mario',
42 | idade: 26,
43 | casado: false,
44 | trabalho: Profissao.Engenheiro // Tudo padronizado e consistente
45 | }
--------------------------------------------------------------------------------
/src/exemplos/exemplo-validacao.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Caso algum dos Ids abaixo não esteja presente no index.html, a função não vai retornar os itens e isso pode causar erros no resto do arquivo.
3 | */
4 | const button = document.getElementById('button');
5 | const input1 = document.getElementById('input1');
6 | const input2 = document.getElementById('input2');
7 |
8 | /**
9 | * A função abaixo não valida se os itens somados são número. Logo situações inesperadas podem ocorrer.
10 | * Por exemplo, somarSemValidar(1, "3") vai devolver "13"
11 | */
12 | function somarSemValidar(numero1, numero2) {
13 | return numero1 + numero2;
14 | }
15 |
16 | button.addEventListener('click', () => {
17 | console.log(somarSemValidar(input1.value, input2.value));
18 | });
19 |
20 | /**
21 | * Na função abaixo uma validação é feita para confirmar se os itens são números e é feita uma conversão caso não sejam.
22 | */
23 | function somarValidando(numero1, numero2) {
24 | if (typeof numero1 !== 'number' || typeof numero2 !== 'number') {
25 | return +numero1 + +numero2;
26 | } else {
27 | return numero1 + numero2;
28 | }
29 | }
30 |
31 | button.addEventListener('click', () => {
32 | console.log(printarSomaValida(input1.value, input2.value));
33 | });
--------------------------------------------------------------------------------
/src/exemplos/functions.ts:
--------------------------------------------------------------------------------
1 | // Como já vimos antes, O typescript infere bastante. Nesse caso ele infere que o retorno dessa função é do tipo number
2 | function adicionar(n1: number, n2: number) {
3 | return n1 + n2;
4 | }
5 |
6 | let resultado: number;
7 | // Por ter inferido que o retorno é um number, a função pode ser usada para atribuir valor para resultado, que é do mesmo tipo.
8 | resultado = adicionar(1, 4);
9 |
10 | /**
11 | * Aqui temos uma função que retorna uma string por causa do uso de toString(). Ela é praticamente igual a função acima, com apenas uma pequena alteração diferindo as duas
12 | * Como o dia a dia dos desenvolvedores é corrido, pequenas mudanças como essa podem ocorrer o tempo todo alterando uma função
13 | * Essa estrutura parece frágil e suscetível a erros e não é isso que queremos com typescript
14 | */
15 | function adicionarNumeros(n1: number, n2: number) {
16 | return n1.toString() + n2;
17 | }
18 | /**
19 | * resultado = adicionarNumeros(1, 4);
20 | * No caso acima um erro vai ser apresentado porque, por inferência, o retorno de adicionarNumeros é do tipo string e resultado espera um number
21 | * Então temos um problema aqui, porque funções podem ser alteradas e isso pode implicar em erros em outras partes do código.
22 | */
23 |
24 | // Uma solução para isso é explicitamente tipar o retorno de uma função. Se algo for modificado dentro dela, o próprio TS pode reclamar caso o retorno não seja number
25 | function adicionarExplicitamenteNumber(n1: number, n2: number): number {
26 | return n1 + n2;
27 | }
28 |
29 | resultado = adicionarExplicitamenteNumber(1, 4);
30 |
31 | // Funções também podem não retornar nada, que é o caso do tipo void
32 | function printarValor(num: number): void {
33 | console.log('O valor é '+ num)
34 | }
35 |
36 | printarValor(3);
37 |
38 | function multiplicarValorPor2(numero: number) {
39 | return numero * 2;
40 | }
41 | /**
42 | * Funções também podem ser passadas como parâmetro. O tipo delas é estruturado assim:
43 | * (parâmetro: tipo do parâmetro) => tipo do retorno
44 | */
45 | function adicionarETratar(n1: number, n2: number, callback: (num: number) => void) {
46 | resultado = n1 + n2;
47 | callback(resultado); // Aqui ela é chamada
48 | }
49 |
50 | adicionarETratar(1, 5, printarValor);
51 | console.log(adicionarETratar(1, 5, multiplicarValorPor2));
--------------------------------------------------------------------------------
/src/exemplos/objetos.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * A inferência de tipo também funciona para objetos.
3 | * Se estiver usando o visual studio code, tente passar o mouse por cima de um objeto não tipado e veja a mágica.
4 | */
5 | const desenvolvedor = {
6 | name: 'Marco',
7 | idade: 25,
8 | salario: 15000
9 | }
10 |
11 | /**
12 | * desenvolvedor.salario = "não tem" devolveria um erro, pois foi inferido que desenvolvedor.salario é do tipo number
13 | * Assim percebemos que enquanto o objeto pode ser escrito de qualquer forma, o uso posterior tem que respeitar a forma como ele foi inicializado
14 | */
15 |
16 | // Nesse caso abaixo a tipagem foi explícita, então é necessário respeitar o tipo durante a criação do objeto.
17 | const carro: {cor: string, numeroDoPneu: number, conversivel: boolean} = {
18 | cor: 'vermelho',
19 | numeroDoPneu: 10,
20 | conversivel: true
21 | }
22 |
23 | /**
24 | * Com esses dois exemplos percebemos que objetos seguem as mesmas regras de variáveis comuns
25 | * Ambos podem ser inicializadas de qualquer forma, mas depois precisam respeitar o tipo
26 | * E caso sejam tipados no início, seu primeiro valor tem que respeitar esse tipo
27 | */
28 |
29 | // Vamos usar pela primeira vez o tipo lista
30 | const estudante: {nome: string, idade: number, materias: string[]} = {
31 | nome: 'Amanda',
32 | idade: 24,
33 | materias: ['Algoritmos', 'Lógica para computação']
34 | }
35 |
36 | function listar(lista: string[]) {
37 | for (const item of lista) {
38 | console.log('- ' + item)
39 | }
40 | }
41 |
42 | // A função reconhece estudante.materias como string[]
43 | listar(estudante.materias)
44 |
--------------------------------------------------------------------------------
/src/respostas/desafio1.ts:
--------------------------------------------------------------------------------
1 | // Resposta 1
2 | const funcionario = {
3 | codigo: 10,
4 | nome: 'João'
5 | };
6 |
7 | // Resposta 2
8 | const funcionario2: {codigo: number, nome: string} = {
9 | codigo: 10,
10 | nome: 'joao'
11 | }
12 |
13 | // Respostas 3 e 4
14 | interface Funcionario { // Já conhece interfaces? https://blog.logrocket.com/types-vs-interfaces-in-typescript/
15 | codigo: number,
16 | nome: string
17 | };
18 |
19 | const funcionarioObj = {} as Funcionario;
20 | funcionarioObj.codigo = 10;
21 | funcionarioObj.nome = 'João';
22 |
23 | const funcionarioObj2: Funcionario = {
24 | codigo: 10,
25 | nome: 'João'
26 | }
--------------------------------------------------------------------------------
/src/respostas/desafio2.ts:
--------------------------------------------------------------------------------
1 |
2 | enum Trabalho {
3 | Atriz,
4 | Padeiro
5 | }
6 |
7 | type Humano = {
8 | nome: string,
9 | idade: number,
10 | profissao: Trabalho
11 | }
12 |
13 | let pessoa1: Humano = {
14 | nome: 'maria',
15 | idade: 29,
16 | profissao: Trabalho.Atriz
17 | };
18 |
19 | let pessoa2: Humano = {
20 | nome: 'roberto',
21 | idade: 19,
22 | profissao: Trabalho.Padeiro
23 | };
24 |
25 | let pessoa3: Humano = {
26 | nome: 'laura',
27 | idade: 32,
28 | profissao: Trabalho.Atriz
29 | };
30 |
31 | let pessoa4: Humano = {
32 | nome: "carlos",
33 | idade: 19,
34 | profissao: Trabalho.Padeiro
35 | }
--------------------------------------------------------------------------------
/src/respostas/desafio3.ts:
--------------------------------------------------------------------------------
1 | export {} // Para não reclamar de variáveis duplicadas
2 | /**
3 | Em todos os casos abaixo de uso do getElementById(), o elemento é potencialmente nulo e ifs são necessários para garantir que seu código vai funcionar da melhor forma.
4 | No entanto, vão existir situações em que o desenvolvedor vai ter certeza de que o campo está lá e ele pode escrever o código da seguinte maneira:
5 | document.getElementById('limpar-saldo')!;
6 | A exclamação no fim é um sinal de que aquele campo não é nulo e que essa função realmente vai trazer algo. Assim, os ifs não são necessários.
7 | Como exemplo, vou seguir essa metodologia no campo 'botaoLimpar'.
8 | */
9 | let botaoAtualizar = document.getElementById('atualizar-saldo');
10 | let botaoLimpar = document.getElementById('limpar-saldo')!;
11 | let soma = document.getElementById('soma')! as HTMLInputElement;
12 | let campoSaldo = document.getElementById('campo-saldo');
13 |
14 | let saldoTotal = 0
15 |
16 | limparSaldo()
17 |
18 | function somarAoSaldo(soma: number) {
19 | if (campoSaldo) {
20 | saldoTotal += soma
21 | campoSaldo.innerHTML = saldoTotal.toString();
22 | limparCampoSoma();
23 | }
24 | }
25 |
26 | function limparCampoSoma() {
27 | soma.value = "";
28 | }
29 |
30 | function limparSaldo() {
31 | if (campoSaldo) {
32 | saldoTotal = 0;
33 | campoSaldo.innerHTML = saldoTotal.toString();
34 | }
35 | }
36 |
37 | if (botaoAtualizar) {
38 | botaoAtualizar.addEventListener('click', () => {
39 | somarAoSaldo(Number(soma.value));
40 | });
41 | }
42 | botaoLimpar.addEventListener('click', () => { // Percebam que aqui o typescript não acusou o botao de ser nulo e não precisei do if. Caso queiram fazer o teste, retirem a exclamação.
43 | limparSaldo();
44 | });
45 |
46 | /**
47 |
Valor a ser adicionado:
48 |
49 |
50 |
"Seu saldo é: "
51 | */
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Basic Options */
6 | // "incremental": true, /* Enable incremental compilation */
7 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
9 | "lib": [
10 | "dom",
11 | "es6",
12 | "DOM.Iterable",
13 | "ScriptHost"
14 | ], /* Specify library files to be included in the compilation. */
15 | "allowJs": false, /* Allow javascript files to be compiled. */
16 | "checkJs": false, /* Report errors in .js files. */
17 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
18 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
19 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
20 | "sourceMap": true, /* Generates corresponding '.map' file. */
21 | // "outFile": "./", /* Concatenate and emit output to single file. */
22 | "outDir": "dist", /* Redirect output structure to the directory. */
23 | "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
24 | // "composite": true, /* Enable project compilation */
25 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
26 | // "removeComments": true, /* Do not emit comments to output. */
27 | // "noEmit": true, /* Do not emit outputs. */
28 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
29 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
30 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
31 |
32 | /* Strict Type-Checking Options */
33 | "strict": true, /* Enable all strict type-checking options. */
34 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
35 | // "strictNullChecks": true, /* Enable strict null checks. */
36 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
37 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
38 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
39 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
40 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
41 |
42 | /* Additional Checks */
43 | // "noUnusedLocals": true, /* Report errors on unused locals. */
44 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
45 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
46 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
47 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
48 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
49 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
50 |
51 | /* Module Resolution Options */
52 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
53 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
54 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
55 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
56 | // "typeRoots": [], /* List of folders to include type definitions from. */
57 | // "types": [], /* Type declaration files to be included in compilation. */
58 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
59 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
60 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
61 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
62 |
63 | /* Source Map Options */
64 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
66 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
67 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
68 |
69 | /* Experimental Options */
70 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
71 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
72 |
73 | /* Advanced Options */
74 | "skipLibCheck": true, /* Skip type checking of declaration files. */
75 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
76 | },
77 | "include": ["src/**/*.ts", "src/desafios/desafio4.js"],
78 | "exclude": ["src/respostas"]
79 | }
--------------------------------------------------------------------------------