typescript2.0 - Propósito de la palabra clave `declare` en TypeScript
¿Cuál es el significado de la palabra clave declare?
type Callback = (err: Error | String, data: Array<CalledBackData>) => void;
vs.
declare type Callback = (err: Error | String, data:Array<CalledBackData>) => void;
No se pueden encontrar documentos que expliquen el propósito de la palabra clave declare en TS. ¿Qué significa esto?
Respuesta #1
Resumen
declare se utiliza para decirle al compilador "esta cosa (generalmente una variable) ya existe, y por lo tanto puede ser referenciada por otro código, además no es necesario compilar esta declaración en ningún JavaScript".
Uso Común:
Agregas una referencia a tu página web a un archivo JavaScript del que el compilador no sabe nada. tal vez sea un script que proviene de algún otro dominio como 'foo.com'. cuando se evalúe, el script creará un objeto con algunos métodos de API útiles y lo asignará al identificador 'fooSdk' en el ámbito global.
Quieres que tu código TypeScript pueda llamar a fooSdk.doSomething(), pero dado que tu compilador no sabe que existe la variable fooSdk, obtendrás un error de compilación.
Luego usas la palabra clave declare como una forma de decirle al compilador "confía en mí, esta variable existe y tiene este tipo". El compilador usará esta declaración para verificar de manera estática otro código, pero no la transcompilará a ningún JavaScript en la salida.
declare const fooSdk = { doSomething: () => boolean }
Las versiones más recientes de Typescript requieren una sintaxis ligeramente diferente:
declare const fooSdk : { doSomething: () => boolean }
En el mismo sentido, puedes agregar la palabra clave declare a las propiedades de la clase para decirle al compilador que no emita ningún código que crearía esta propiedad, suponiendo que tengas tu propio código que la crearía y que el compilador no conoce o no entiende.
Tu ejemplo específico es diferente ya que estás declarando un tipo, no una variable; los tipos ya no se compilan en ningún JavaScript. No sé si hay alguna razón para declarar un tipo.
Respuesta #2
Aquí hay un ejemplo del mundo real.
Tengo una aplicación React en TypeScript que utiliza Webpack Hot Middleware. Webpack Hot Middleware no está escrito en TypeScript, sino en el buen y viejo JavaScript. Por lo tanto, no tiene declaraciones de tipo con las que el compilador de TypeScript pueda verificar.
Cuando ejecuto mi código, el objeto module del Webpack Hot Middleware existe, y puedo hacer console.log de él a pesar de que es el buen y viejo JavaScript escondido en mi nueva y elegante aplicación de TypeScript React.
El objeto module también tiene claves, como module.hot, y las claves pueden tener valores. Pero el compilador de tiempo de diseño de TypeScript (al menos en VSCode) dibuja una línea ondulada roja debajo diciendo property 'hot' does not exist. ¡Pero sí existe!
Para que el compilador de TypeScript esté de acuerdo, decláralo así:
declare let module: any
El objeto module existente, ahora tiene un tipo de any, lo que hace que el compilador de TypeScript esté contento ahora, la línea ondulada roja desapareció y ahora puedo continuar compilando y escribiendo mi otro código.
Si eliminas la palabra clave declare y solo escribes let module: any, no se compilará, y en su lugar dirá que 'module' ya existe. Eso es lo que significa "ambient" en la respuesta aceptada.
Respuesta #3
De la documentación de TypeScript:
Typescript - Trabajando con otras bibliotecas de JavaScript
Para describir la forma de las bibliotecas que no están escritas en TypeScript, necesitamos declarar la API que la biblioteca expone. Dado que la mayoría de las bibliotecas de JavaScript exponen solo algunos objetos de nivel superior, los espacios de nombres son una buena manera de representarlos.
Llamamos a las declaraciones que no definen una implementación “ambientales”. Normalmente, estas se definen en archivos .d.ts. Si estás familiarizado con C/C++, puedes pensar en estas como archivos .h. Veamos algunos ejemplos.
Espacios de nombres ambientales
La popular biblioteca D3 define su funcionalidad en un objeto global llamado d3. Debido a que esta biblioteca se carga a través de una etiqueta (en lugar de un cargador de módulos), su declaración utiliza espacios de nombres para definir su forma. Para que el compilador de TypeScript vea esta forma, utilizamos una declaración de espacio de nombres ambiental. Por ejemplo, podríamos comenzar a escribirlo de la siguiente manera:
D3.d.ts (extracto simplificado) :
declare namespace D3 { export interface Selectors { select: { (selector: string): Selection; (element: EventTarget): Selection; }; } // (...) }
Respuesta #4
Puedes usar declare para informar al compilador sobre los tipos antes de escribir cualquier código de implementación y TypeScript estará feliz.
declare function foo(name: string): string
Respuesta #5
Considera este escenario: Tienes un proyecto de Typescript. Luego decides escribir un módulo en JavaScript por cualquier razón y usarlo en tu código de Typescript.
// getMyName.js
module.exports = function getMyName(name) {
return name;
}
Luego lo importas en tu código TypeScript
// myCode.ts
import getMyName from 'getMyName'; //getMyName is a JS module not typescript
Al importar ese módulo de JS (la opción del compilador allowJs debería estar configurada en false; de lo contrario, los archivos JS se resolverán sin ninguna definición de tipos), ¡el compilador de TypeScript se queja de que ese módulo no es un módulo en absoluto!
Could not find a declaration file for module '/absolute/path/to/getMyName.ts'Esto se debe a que Typescript no se resuelve a código JS por sí mismo. Para sortear este problema, debemos proporcionar una definición de tipo (filename.d.ts) para nuestro módulo JS. Para hacerlo, puedes usar declare y export.
// getMyName.d.ts
declare function getMyName(name: string): string;
export default getMyName;
Después de eso, cuando importamos nuestro módulo JS, TypeScript no se queja de nada porque ahora tiene acceso a los tipos.
