Neste curso ensinaremos como aplicar, na prática, o TypeScript em aplicações WEB, sites e etc. Além disso, veremos dicas e boas práticas de como resolver problemas cotidianos com o TypeScript e a estruturação desta tecnologia dentro de projetos WEB.
- CURSO https://www.schoolofnet.com/curso/frontend/typescript/typescript-na-pratica/
- SITE OFICIAL TYPESCRIPT - https://www.typescriptlang.org/
- ACRONIMOS
- LTS - long-term support, ou Suporte de longo prazo
- ESTRUTURA DE PASTA DO PROJETO
- /
- /public/
- posts.html
- /src/
- posts.ts
-
Instalar a versao LTS do nodejs e npm: https://nodejs.org/en/download/
-
Verificar versão: " node -v "
-
Instalação global do typescript: " npm install -g typescript@2.6.1 "
-
Verificar versao do compilador typescript(tsc): " tsc -v "
-
Compilar com versao global: " tsc /src/posts.ts "
-
Criar arquivo .tsconfig.json na raiz do projeto -> A presença de um arquivo tsconfig.json em um diretório indica que o diretório é a raiz de um projeto TypeScript. O arquivo tsconfig.json especifica os arquivos raiz e as opções do compilador necessárias para compilar o projeto.
-
Configurar as opções(tsconfig.json) do compilador typescript:
/** * tsconfig.json * Chamando 'tsc' sem arquivos de entrada, * nesse caso o compilador procura pelo arquivo tsconfig.json iniciando no diretório atual * e continuando a cadeia de diretórios pai */ { "compilerOptions": { "target" : "ES5" , // Especificação do ECMAScript utilizada "rootDir" : "src/" , // Path raiz contendo arquivos .ts "outDir" : "public/js" , // Path com saída transpilada do arquivo .js }, "files": [ "src/posts.ts" ] }
- Referências
- referencia : https://www.typescriptlang.org/tsconfig
- documentacao1 : https://www.typescriptlang.org/docs/handbook/compiler-options.html
- documentacao2 : https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
- compilerOptions
-
--target string "ES3" Specify ECMAScript target version:
► "ES3" (default). ► "ES5". ► "ES6"/"ES2015" ► "ES2016" ► "ES2017" ► "ES2018" ► "ES2019" ► "ES2020" ► "ESNext"
-
--rootDir string (common root directory is computed from the list of input files) Specifies the root directory of input files. Only use to control the output directory structure with --outDir.
-
--outDir string Se especificado, os arquivos .js (assim como os arquivos .d.ts, .js.map etc.) serão emitidos nesse diretório. A estrutura de diretórios dos arquivos de origem originais é preservada; consulte rootDir se a raiz calculada não for o que você pretendia.
-
- files ['path/arquivo1.ts','path/arquivo2.ts'] : Especifica uma lista de arquivos que pode ser incluidas(import) no programa. Um error é lançando se qualquer arquivo desta lista nao for encontrado.
- Referências
-
Testar saída da nova configuração do 'tsconfig.json': " tsc " // um novo js será gerado na pasta public/
-
Em desenvolvimento fica interessante usar o modo watch: tsc -w // acompanha as modifições e transpila .js novamente.
-
Em produção: Transpile any files referenced in with the compiler settings from tsconfig.production.json tsc --project tsconfig.production.json
-
criar tsconfig.json na raiz do projeto:
{ "compilerOptions": { "target" : "ES5" , // Especificação do ECMAScript utilizada "rootDir" : "src/" , // Path raiz contendo arquivos .ts "outDir" : "public/js" , // Path com saída transpilada do arquivo .js }, "files": [ "src/posts.ts" ] }
-
Transpilar com watch:
./node_modules/.bin/tsc -w
- HTML SOLTO PUXANDO JS EXPORTADO PELO TSC
- CAPTURA DE EVENTOS CLICK PARA LINKAR OS BLOCOS(DIVS): LIST E FORM
- REPETIÇÃO DE CAPTURA DE ELEMENTOS DOM ESPALHADOS
- DEIXAR DE USAR VARIAVEIS, E REPETIR NOMES PELO CODIGO
- NAO USAR TOKENS 'elemento-x-to-y'
- Será que o metodo precisa ser chamado fora da classe? Senao use o modificador
private
class BoxPostForm { private boxList: BoxPostList; static boxTokenId:string = 'box-post-form'; ... }
- Criação de variaveis ou propriedades estáticas para uso sem que precise instanciar a classe
class BoxPostForm { // private boxList: BoxPostList; static boxTokenId:string = 'box-post-form'; static buttonToken:string = 'box-post-form>button[type=button]'; static box: HTMLDivElement = (<HTMLDivElement> document.getElementById(BoxPostForm.boxTokenId) ); // Div Form static button: HTMLButtonElement = document.querySelector(`#${BoxPostForm.buttonToken}`); // Botao Listar meus posts constructor() {} }
- Poder trabalhar com typescript no debug do browser.
- Informa para o browser os arquivos que precisam ser mapeados para visualização:
./node_modules/.bin/tsc --sourceMap
- Não funcionou com lite-serve
-
Orientação a eventos
-
Indepency - Construir comunicação entre duas classes sem que elas se conheçam
-
Pattern de orientacao a eventos:
/** * Conceito de orientação a eventos(listeners) */ class EventManager { private listeners = {}; /** * Adiciona funcoes/procedures para cada ouvinte * @param eventName * @param callable */ addListener(eventName: string, callable: ()=>void ) { /** * Representacao de um listener * Cada posicao associativa/token do objeto recebe um array de funcoes * this.listerners['cantar'] = [func1,func2,func3]; * ex: { * 'mostrar'=>function(){ * mostrarAlgo() * } * } */ if( !(this.listeners[eventName] instanceof Array) ){ this.listeners[eventName] = []; } this.listeners[eventName].push(callable); } runEvent(eventName: string) { // console.log(this.listeners[eventName]) if( !(this.listeners[eventName] instanceof Array) ){ this.listeners[eventName] = []; } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of for(let callable of this.listeners[eventName]){ callable(); } } }
-
Declaração para chamar dentro de classes distintas
Na classe que ocorre o evento adiciona o ouvinte
// Ouvinte - Quando formulario for ocultado this.eventManager.addListener('box-post-form-click-hidden',()=>{ // mostro a listagem this.showBox(); });
Na classe que quero disparar o evento criado acima
// disparar evento quando o formulario ocultar - exibir box list this.eventManager.runEvent('box-post-form-click-hidden');
- Referencia : https://www.typescriptlang.org/docs/handbook/interfaces.html
- Criação de interfaces como tipos para EventManager.
- Criando consistencia e segurança de código com interfaces Listerners e ListenerInterface
- Uso do padrão Indexable Types, ex: { [indice:string]: Array }
interface ListenerInterface { ():void; } interface Listeners { [eventName: string]: Array<ListenerInterface> } class EventManager { /** * Indexable Types * - Representacao shortHand de um objeto específico(iteravel), com indice associativo(eventName:string) definido. * Neste indice comporta SOMENTE, um array com itens do tipo ListernerInterface * * Qualquer outra representacao de objeto gera um erro * */ private listenersShortHand: { [eventName: string]: Array<ListenerInterface> } = {}; // representacao shortHand de um Indexable Types private listeners: Listeners = {}; ... }
- Criar variaveis para guardar os tokens do eventos
class BoxPostList { static boxTokenId:string = 'box-post-list'; static buttonToken:string = 'box-post-list>button[type=button]'; static EVENT_CLICK_HIDDEN_BOX_LIST = 'box-post-list-click-hidden'; constructor(private eventManager: EventManager){ // executar evento ja registrado this.eventManager.runEvent(BoxPostList.EVENT_CLICK_HIDDEN_BOX_LIST); } }
-
Controllers - Separação do arranque de um sistema dentro de uma classe responsavel
/** * Organização dos scripts em conceitos de páginas */ class PostsPage { constructor(private eventManager: EventManager) { this.init(); } private init() { new BoxPostForm(this.eventManager); new BoxPostList(this.eventManager); } } new PostsPage( new EventManager() );
-
Sistema de Carregamento de Módulos
-
Utilização do 'AMD' - Asynchronous module definition - https://en.wikipedia.org/wiki/Asynchronous_module_definition
-
Melhoria de Performe e Reuso de código, tal como desacomplamento do sistema.
-
Módulos (https://www.typescriptlang.org/docs/handbook/modules.html) são importados ou exportados pelas palavras reservadas 'export' ou 'import'.
-
Passos para implementação completa do sistema de módulos:
-
Nomeação Kebeb para arquivos separados como módulo. ex: 'event-manager.ts'
-
Refatorar todo typeScript para exportar e importar classes dependentes.
export default EventManager {};
ou
import EventManager from './src/event-manager';
-
Se for uma uníca classe do módulo a ser exportada usa-se
export default className
; -
Resolver erro gerado por falta da lib require e falha do modulo 'exports not defined'. Por default o
tsconfig.json
define oCommonJS
como gerenciandor de módulos, deve-se alterar paraAMD
:/** documentacao: https://www.typescriptlang.org/docs/handbook/compiler-options.html */ { "compilerOptions": { "target" : "ES5" , // Especificação do ECMAScript utilizada "module" : "AMD" , // default é CommonJS "rootDir" : "src" , // Path raiz contendo arquivos .ts "outDir" : "public/js" , // Path com saída transpilada do arquivo .js "sourceMap" : true }, "files": [ "src/posts.ts" ] }
-
A compilação do código agora usará o módulo
define
para carregamento por ordem do array. E precisará do módulo/librequireJS
-
Utilizando CDN cdnjs : https://cdnjs.com/libraries/require.js
-
- Instalação e uso do requireJS(requirejs.org):
- Colocar script no topo do carregamento da tag script ou antes das classes typescript do projeto
<!-- Carregamento no módulo requireJS --> <script data-main="app" src="lib/require.min.js"></script>
- data-main informa para carregar o arquivo/modulo post apos leitura completa da lib requireJS (evita erro de pilha de carregamento)
- Este bloco é customizado para olhar para pasta lib e usar
requirejs.config()
- Gerar um caminho path chamado
app
para olhar para o caminho/js/posts.js
- Precisa gerar o script de arranque do
requireJS
, no arquivo app.js, na raiz:/** * Configuração de arranque do requirejs */ requirejs.config({ baseUrl : './lib', // base/raiz de execução e escopo do requirejs paths : { app: '../js' // path customizado para voltar 1 nivel com nome de app olhando para ../js } }); // inicia o requirejs de fato requirejs(['app/posts'], function(){ console.log('requirejs carregou'); })
- É necessário usar em modo servidor de prod. simule com lite-serve
- instalacao:
npm i -g live-server
- configuração:
Criar um arquivo bs-config.json
e incluir:{ "port": 8000, "files": ["./public/**/*.{html,htm,css,js}"], "server": { "baseDir": "./public" } }
- usando como dev --save-dev no cli >
./node_modules/.bin/live-server
na raiz (onde encontra-se o arquivo bs-config.json) - descricao : O servidor de nó de desenvolvimento leve que serve um aplicativo da Web, abre-o no navegador, atualiza quando o html ou o javascript são alterados, injeta alterações de CSS usando soquetes e possui uma página de fallback quando uma rota não é encontrada.
- referencia: https://www.npmjs.com/package/lite-server
-
instalacao: npm install -g live-server
-
uso no cli: c:\path-project> live-server public\
-
descrição :É um pequeno servidor de desenvolvimento com capacidade de recarga ao vivo. Use-o para carregar seus arquivos HTML / JavaScript / CSS, mas não para implantar o site final.
- Há duas razões para usar isso:
- As solicitações AJAX não funcionam com o protocolo file: // devido a restrições de segurança, ou seja, você precisa de um servidor se o site buscar conteúdo por meio de JavaScript.
- O recarregamento automático da página após alterações nos arquivos pode acelerar o desenvolvimento.
- Você não precisa instalar nenhum plug-in de navegador ou adicionar manualmente trechos de código às suas páginas para que a funcionalidade de recarregamento funcione, consulte a seção "Como funciona" abaixo para obter mais informações. Se você não deseja / precisa da atualização ao vivo, provavelmente deve usar algo ainda mais simples, como o seguinte linux baseado em Python:
python -m SimpleHTTPServer
-
referencia: https://www.npmjs.com/package/live-server