Pesquisa de site

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.

Artigos relacionados