Qual é o exemplo mais simples possível de onde a palavra-chave `declare` é útil em TypeScript?
Eu li documentos (isto é, este) e alguns posts de blog sobre a palavra-chave declare no TypeScript e ainda não a entendo. O que eu gostaria é de um exemplo claro do seu uso mais simples.
Aqui está a linha de raciocínio que inicialmente criei para chegar a este exemplo mais simples (que provavelmente está incorreto):
Tenha um arquivo .js que exporte algo (sem tipagem porque este é JS puro).
Faça um arquivo .ts importar o que quer que o arquivo .js tenha exportado.
O que precisa ser exportado e importado (um objeto? uma função?) para que eu veja o TS mostrar um erro que poderia ser corrigido usando declare?
Resposta #1
Seu exemplo está correto. Por exemplo, você está usando um módulo node que é escrito em javascript puro (não há tipagens disponíveis), então o compilador ts irá notar isso (já que ele procura pelas tipagens, que geralmente estão no módulo node ou em um @typings/package extra).
Você, no entanto, pode fornecer essas tipagens você mesmo, dizendo ao tscompiler no tsconfig.json para olhar o arquivo xyz.d.ts para as tipagens, por exemplo.
tsconfig.json
{
"files": [
"typings/index.d.ts"
]
}
O index.d.ts é onde todos os seus tipos personalizados são reunidos, o que pode parecer assim
index.d.ts
/// <reference path="custom-typings.d.ts" />
e o custom-typings.d.ts contém as tipagens reais. É aqui que a palavra-chave declare entra em cena
custom-typings.d.ts
declare module "the-untyped-node-module-name" {
export default class TheNodeModuleClass {
static showNotification(string: any): void;
}
}
Agora o compilador TypeScript sabe que existe uma TheNodeModuleClass em the-untyped-node-module-name que possui a função estática showNotification.
Para mais informações, veja Módulos TypeScript.
Este é um caso de uso para a palavra-chave declare. Existem, é claro, mais casos como declare var, declare function, declare class e assim por diante.
Resposta #2
A resposta de Murat Karagöz acima apontou na direção certa, e esta resposta fornecerá código real com o exemplo mínimo de onde usaríamos declare.
Aqui está um módulo npm muito simples: apenas um arquivo index.js que exporta um objeto com um método. Não há declarações de tipo aqui porque é apenas JS.
const item = {
price: 5,
name: 'item1',
};
export const MyModuleObject = { method: () => item };
Aqui está um projeto npm TypeScript muito simples, com uma dependência: o projeto JS vinculado acima. Este último é, portanto, um módulo npm importado sem tipagens. Aqui está o arquivo index.ts no projeto TS:
/// <reference path="index.d.ts"/>
import { MyModuleObject } from 'npmModule';
import { LocalModuleObject } from './module';
// Without the "reference path" line, TS complains in line 3 that it could not find a declaration file for 'npmModule'.
// In this case, the import has type any, so TS does not complain about the call below to an inexistent method.
// When we uncomment line 1, we get a TS error on line 8: property 'test' does not exist on type { method: ... }
MyModuleObject.test();
// TS complains that test does not exist on type { method: ... }
// Here we did not need to have a `declare` statement in a type definitions file for TS to know this because here TS is
// using contextual typing:
LocalModuleObject.test();
Abaixo está o código para index.d.ts:
declare module "npmModule" {
export const Item: {
price: number,
name: string
}
export const MyModuleObject: {
method: () => Item
}
}
E o código para ./module:
export const LocalModuleObject = { method: () => 10 };
Como este é um exemplo de por que se usa declare - eu coloquei isso nos comentários de index.ts, mas deixe-me explicar com mais palavras. index.ts está importando um objeto de um módulo externo (um que está em node_modules), e outro objeto de um módulo local (./module.js). Ambos os módulos estão exportando um objeto com um método chamado method. Em index.ts, estou chamando um método inexistente test em cada um desses objetos.
O TS usa tipagem contextual na importação do módulo local, então ele sabe que test não existe no objeto. Isso não acontece na importação do objeto no módulo externo: essa importação é importada com o tipo any. Portanto, o TS não reclama sobre a chamada ao método inexistente test. No entanto, ele reclama que não há tipagens para o módulo externo, então isso é uma dica de que any implícito está sendo usado.
Podemos remediar esta última reclamação definindo um index.d.ts que fornece tipagens para a biblioteca externa. É aqui que declare module é usado: declara o que o módulo npmModule exporta; npmModule é a importação externa. No index.ts devemos adicionar a linha /// <reference path="index.d.ts"/> para que o TS saiba onde procurar pelos tipos.
