¿Qué significa `export as namespace` en un archivo .d.ts de TypeScript?
He estado leyendo algunos archivos de declaración en DefinitelyTyped y a menudo me he encontrado con archivos como este:
declare function domready(callback: () => any) : void;
export = domready;
export as namespace domready;
Entiendo las dos primeras líneas: declarar una función y exportar esa función como el objeto del módulo. Pero, ¿qué hace la última línea? ¿Necesito esto en mi archivo de declaraciones? ¿Qué hace?
Respuesta #1
Esta es una declaración de módulo UMD.
Si aún no estás familiarizado, UMD es un patrón de creación que permite que la misma biblioteca de JavaScript se use como una variable global (una que se puede acceder desde cualquier lugar) o como un módulo (uno que se carga específicamente en tiempo de ejecución) dependiendo del entorno.
Muchas bibliotecas están escritas con el patrón UMD. Por ejemplo, puede escribir
moment.parse("12-31-2017")
en el navegador, pero escribe código así en node.js:
const m = require("moment");
m.parse("12-31-2017")
Cuando escribes una declaración export como export function parse, TypeScript sabe que estás describiendo un módulo como en el segundo bloque de código. Pero si la biblioteca para la que estás escribiendo un archivo .d.ts también crea una variable global, puedes describir esa variable global usando la sintaxis de declaración de módulo UMD:
export as namespace the_global_identifier;
Algunas bibliotecas UMD siempre crearán un global, mientras que otras deben ser importadas si se cargan en un entorno donde hay un sistema de módulos presente. En general, las bibliotecas no documentan claramente qué comportamiento usan, lo que significa que los autores de archivos de declaración realmente no saben qué esperar, lo que significa que TypeScript es conservador y solo permitirá el acceso al identificador global si el archivo que lo referencia no es un módulo.
Si estás escribiendo un archivo de declaración y no estás seguro de si la biblioteca es UMD o no, busca patrones que se vean así:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.mymodule = global.mymodule || {})));
}(this, function (exports) { 'use strict';
function myFunction() {
console.log('hello world');
}
}));
Este es el característico olor de UMD: mucho uso de typeof para comprobar "exports", "module" y "define" seguido de una asignación a un parámetro "exports" dado a un gran cuerpo de función. Si no ves esto en el código de la biblioteca, casi con seguridad no es un módulo UMD y no deberías escribir una declaración export as namespace.
