Começando deste ponto? Você pode fazer o download completo do projeto do capítulo anterior e continuar seus estudos a partir deste capítulo.
Hoje a definição das nossas classes vivem no escopo global. Além disso, para que o desenvolvedor saiba quais são as classes disponíveis pelo autocomplete do TypeScript ele precisa saber pelo menos parte do nome. Contudo, TypeScript oferece o conceito de namespace. Podemos agrupar classes dentro de um mesmo namepace e acessá-las através dele.
No caso, vamos envolver todas as classes dentro de alurabank/app/views
no namespace Views
:
namespace Views {
export abstract class View<T> {
protected _elemento: JQuery;
constructor(seletor: string) {
this._elemento = $(seletor);
}
update(model: T) {
this._elemento.html(this.template(model));
}
abstract template(model: T): string;
}
}
Veja que além do namespace, é necessário adicionarmos a instrução export
para que a classe esteja disponível.
Agora, vamos alterar MensagemView
e NegociacaoView
adicionando-os no mesmo namespace. Agora, para estendermos da classe View
precisaremos usar a sintaxe Views.View
:
namespace Views {
export class MensagemView extends Views.View<string> {
template(model: string): string {
return `<p class="alert alert-info">${model}</p>`;
}
}
}
namespace Views {
export class NegociacoesView extends Views.View<Negociacoes> {
template(model: Negociacoes): string {
return `
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>DATA</th>
<th>QUANTIDADE</th>
<th>VALOR</th>
<th>VOLUME</th>
</tr>
</thead>
<tbody>
${model.paraArray().map(negociacao =>
`
<tr>
<td>${negociacao.data.getDate()}/${negociacao.data.getMonth() +1}/${negociacao.data.getFullYear()}</td>
<td>${negociacao.quantidade}</td>
<td>${negociacao.valor}</td>
<td>${negociacao.volume}</td>
<tr>
`
).join('')}
</tbody>
<tfoot>
</tfoot>
</table>
`;
}
}
}
Agora, em NegociacaoController
:
class NegociacaoController {
private _inputData: JQuery;
private _inputQuantidade: JQuery;
private _inputValor: JQuery;
private _negociacoes = new Negociacoes();
private _negociacoesView = new Views.NegociacoesView('#negociacoesView');
private _mensagemView = new Views.MensagemView('#mensagemView');
// código posterior omitido
Excelente, mas essa solução não resolve o problema de termos que nos preocupar com a ordem de importação dos scripts em index.html
, um dos tendões de Aquiles do mundo JavaScript. É por isso que o TypeScript aceita também o sistema de módulos do ES2015. Será ele que utilizaremos, em vez do sistema de namespace.
A sintaxe de módulos do ES2015 considera cada script um módulo e através das instruções import
e export
importamos e exportamos artefatos respectivamente.
Adequando todos os arquivos para o sistema de módulos do ES2015:
export abstract class View<T> {
protected _elemento: JQuery;
constructor(seletor: string) {
this._elemento = $(seletor);
}
update(model: T) {
this._elemento.html(this.template(model));
}
abstract template(model: T): string;
}
import { View } from './View';
import { Negociacoes } from '../models/Negociacoes';
export class NegociacoesView extends View<Negociacoes> {
template(model: Negociacoes): string {
return `
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>DATA</th>
<th>QUANTIDADE</th>
<th>VALOR</th>
<th>VOLUME</th>
</tr>
</thead>
<tbody>
${model.paraArray().map(negociacao =>
`
<tr>
<td>${negociacao.data.getDate()}/${negociacao.data.getMonth() +1}/${negociacao.data.getFullYear()}</td>
<td>${negociacao.quantidade}</td>
<td>${negociacao.valor}</td>
<td>${negociacao.volume}</td>
<tr>
`
).join('')}
</tbody>
<tfoot>
</tfoot>
</table>
`;
}
}
import { View } from './View';
export class MensagemView extends View<string> {
template(model: string): string {
return `<p class="alert alert-info">${model}</p>`;
}
}
import { Negociacao } from './Negociacao';
export class Negociacoes {
private _negociacoes: Negociacao[] = [];
adiciona(negociacao: Negociacao): void {
this._negociacoes.push(negociacao);
}
paraArray(): Negociacao[] {
return [].concat(this._negociacoes);
}
}
export class Negociacao {
constructor(private _data: Date, private _quantidade: number, private _valor: number) {}
get data() {
return this._data;
}
get quantidade() {
return this._quantidade;
}
get valor() {
return this._valor;
}
get volume() {
return this._quantidade * this._valor;
}
}
import { NegociacoesView } from '../views/NegociacoesView';
import { MensagemView } from '../views/MensagemView';
import { Negociacoes } from '../models/Negociacoes';
import { Negociacao } from '../models/Negociacao';
export class NegociacaoController {
private _inputData: JQuery;
private _inputQuantidade: JQuery;
private _inputValor: JQuery;
private _negociacoes = new Negociacoes();
private _negociacoesView = new NegociacoesView('#negociacoesView');
private _mensagemView = new MensagemView('#mensagemView');
constructor() {
this._inputData = $('#data');
this._inputQuantidade = $('#quantidade');
this._inputValor = $('#valor');
this._negociacoesView.update(this._negociacoes);
}
adiciona(event: Event) {
event.preventDefault();
const negociacao = new Negociacao(
new Date(this._inputData.val().replace(/-/g, ',')),
parseInt(this._inputQuantidade.val()),
parseFloat(this._inputValor.val())
);
this._negociacoes.adiciona(negociacao);
this._negociacoesView.update(this._negociacoes);
this._mensagemView.update('Negociação adicionada com sucesso!');
}
}
import { NegociacaoController } from './controllers/NegociacaoController';
const controller = new NegociacaoController();
$('.form').submit(controller.adiciona.bind(controller));
Isso ainda não é suficiente, precisamos utilizar um loader, uma biblioteca que seja capaz de carregar o módulo app.js
e a partir deles carregar todos os demais módulos.
Vamos alterar o arquivo tsconfig.json
e indicar para o TypeScript que ele deve usar o sistema de módulos do System.js
:
{
"compilerOptions": {
"target": "es6",
"outDir": "app/js",
"noEmitOnError": true,
"noImplicitAny": true,
"removeComments": true,
"module": "system"
},
"include": [
"app/ts/**/*"
]
}
Agora, quando nossos arquivos são compilados, eles possuem essa estranha estrutura:
System.register(["../views/NegociacoesView", "../views/MensagemView", "../models/Negociacoes", "../models/Negociacao"], function (exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var NegociacoesView_1, MensagemView_1, Negociacoes_1, Negociacao_1, NegociacaoController;
return {
// código posterior omitido
Por fim, vamos importar o loader utilizá-lo para carregar js/app/js
. É a partir dele que os demais serão carregados.
<div id="negociacoesView"></div>
<script src="lib/jquery.min.js"></script>
<script src="lib/system.js"></script>
<script>
System.defaultJSExtensions = true;
System.import('js/app.js').catch(err => console.error(err));
</script>
Contudo, isso não é suficiente. Loaders usam XMLHttpRequest, ou seja, realizam requisições Ajax para baixar os módulos e para isso precisamos de um servidor que disponibiliza nossa aplicação para o browser.
O curso TypeScript parte 2: Mais técnicas e boas práticas possui 203 minutos de vídeos, em um total de 61 atividades. Gostou? Conheça nossos outros cursos de JavaScript em Front-end, ou leia nossos artigos de Front-end.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Acesso por 1 ano
Estude 24h/dia onde e quando quiser
Novos cursos todas as semanas