Trabalhando com Arquivos de Declaração em TypeScript
Para estabelecer a conexão com arquivos de scripts JavaScript externos em TypeScript (TS), utilizamos arquivos de declaração ou de cabeçalho. Esses arquivos possuem a extensão .d.ts
e descrevem a sintaxe e a estrutura de funções e propriedades que podem ser usadas no programa, sem fornecer uma implementação concreta. Seu funcionamento é semelhante ao dos arquivos com extensão .h
em linguagens como C/C++. Eles atuam como uma camada de encapsulamento sobre bibliotecas JavaScript.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Programício</title>
</head>
<body>
<h2>Aplicação em TypeScript</h2>
<script>
let message = "Hello TypeScript!";
</script>
<script src="app.js"></script>
</body>
</html>
Neste caso, para simplificar, a variável message
é definida na própria página web, embora também pudesse ser definida em um arquivo JS externo.
Suponha que queremos usar essa variável message
no código TypeScript no arquivo app.ts
:
console.log(message);
Ao executar a aplicação, o compilador TS não conseguirá compilar o programa, pois, para o código TypeScript, a variável global ainda não existe. Isso ocorre porque o compilador do TypeScript exige que todas as variáveis estejam explicitamente declaradas e tipadas no próprio código TypeScript. Esse comportamento está alinhado aos princípios do TypeScript, que visam garantir maior segurança e previsibilidade no código.
Para resolver esse problema, é necessário incluir a definição da variável global utilizando arquivos de declaração. Para isso, devemos adicionar ao projeto um novo arquivo chamado globals.d.ts
com o seguinte conteúdo:
declare let message: string;
Com a palavra-chave declare
, incluímos a definição da variável global no programa TS.
Assim, teremos a seguinte estrutura de projeto:
. ├── app.ts ├── globals.d.ts └── index.html
Compilação
Se compilarmos passando o nome do arquivo ao compilador no console:
tsc app.ts
Neste caso, o compilador não encontrará automaticamente o arquivo globals.d.ts
. Precisamos, então, especificar explicitamente a localização do arquivo globals.d.ts
no arquivo app.ts
usando a diretiva reference
:
/// <reference path="globals.d.ts" />
console.log(message);
Se confiarmos no arquivo de configuração tsconfig.json
, executando simplesmente o comando:
tsc
Neste caso, não é necessário especificar a diretiva /// <reference path="globals.d.ts" />
.
Da mesma forma, podemos incluir outros componentes do código JavaScript — funções, objetos e classes. Vamos examinar como fazê-lo.
Funções
Suponha que, no código JS de uma página web, estejam declaradas as seguintes funções:
let message = "Hello TypeScript!";
function hello() {
console.log(message);
}
function sum(a, b) {
return a + b;
}
A função hello()
exibe o valor da variável message
no console, e a função sum()
retorna a soma de dois números.
E suponha que, no código TS, queremos chamar essas funções:
hello();
let result = sum(2, 5);
console.log(result);
Nesse caso, a inclusão no arquivo globals.d.ts
ficaria assim:
declare function hello(): void;
declare function sum(a: number, b: number): number;
Objetos
Suponha que, no código JavaScript, exista o seguinte objeto:
const tom = {
name: "Tom",
age: 37,
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
},
};
Vamos usar esse objeto no código TypeScript:
tom.print();
Nesse caso, a definição do objeto no arquivo globals.d.ts
seria:
declare const tom: { name: string; age: number; print: () => void };
Array de Objetos
Pode haver dificuldades ao incluir arrays de objetos. Por exemplo, suponha que haja o seguinte objeto JavaScript:
var points = [
{ X: 10, Y: 34 },
{ X: 24, Y: 65 },
{ X: 89, Y: 12 },
];
Para esse array de objetos, no arquivo globals.d.ts
, podemos definir uma interface correspondente a cada objeto individual e incluir um array de objetos dessa interface, que contém duas propriedades X
e Y
:
interface IPoint {
X: number;
Y: number;
}
declare var points: IPoint[];
E no TypeScript poderemos usar esse array:
for (let point of points) {
console.log(`Ponto com coordenadas X =
${point.X} Y = ${point.Y}`);
}
Saída no console do navegador:
Ponto com coordenadas X = 10 Y = 34 Ponto com coordenadas X = 24 Y = 65 Ponto com coordenadas X = 89 Y = 12
Classes
Vamos considerar mais um exemplo: incluir em TypeScript classes definidas em JavaScript. Suponha que, no código JavaScript, seja definida a seguinte classe Person
:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
display() {
console.log(this.name, this.age);
}
}
Para essa classe, no arquivo globals.d.ts
, definimos a seguinte declaração de classe:
declare class Person {
name: string;
age: number;
constructor(name: string, age: number);
display(): void;
}
Especificamos todos os campos e métodos da classe; os métodos (incluindo o construtor) não têm implementação: apenas definimos os parâmetros, seus tipos e o tipo do valor retornado.
E no código TypeScript usamos essa classe:
let tom = new Person("Tom", 37);
tom.display(); // Tom 37
console.log(tom.name); // Tom