node.js - Skriva .d.ts-fil så att jag kan dela konstanter med JavaScript och TypeScript?
Jag arbetar på ett Node.js-projekt som av historiska skäl involverar både TypeScript och JavaScript. Jag skulle vilja sätta upp några projektövergripande konstanter som kan användas i båda språken. Självklart: skriv en .js-fil med konstanterna, och en .d.ts-fil som inkluderar typerna för TypeScripts användning. Men nej: flera timmar av att brottas med problemet (och läsa manualen) har inte lett någonstans.
Här är mitt första försök med konstanterfilen:
// constants.js
const MY_CONST_1 = 1;
exports.MY_CONST_1 = MY_CONST_1;
... och JavaScript som använder det:
// consumer.js
let constants = require('./constants');
let one = constants.MY_CONST_1;
Det fungerar bra, men när jag försöker det uppenbara i TypeScript:
// consumer.ts
import * as constants from './constants';
let one: number = constants.MY_CONST_1;
Nej: error TS2307: Kan inte hitta modul './constants'. Så, jag måste skriva en constants.d.ts-fil, i samma katalog som constants.js-filen, eller hur? Låter enkelt, men ett halvdussin olika försök har gett precis ingenting. Oavsett vad jag gör klagar Typescript error TS2306: Filen '/Users/griscom/Documents/Work/test/constants.d.ts' är inte en modul.
Så, hur skulle en framgångsrik constants.d.ts-fil se ut? Eller, om jag skulle behöva göra ändringar i constants.js för att allt ska fungera, vilka skulle de vara?
P.S. Här är min tsconfig.json-fil:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true,
"noImplicitReturns": true
}
}
(Detta verkar som ett så enkelt och självklart behov; det är frustrerande hur otydlig processen är.)
Svar #1
Alternativ 1: allowJs
Försök använda kompilatoralternativet allowJs: true. Detta kommer att tillåta din ursprungliga import från ./constants att fungera även om det är en .js-fil, utan att behöva skapa en separat .d.ts-fil. TypeScript kommer att förstå härledbara typer från .js-filen, till exempel kommer du att få typkontroll mot MY_CONST_1 som ett nummer.
Som du sa i din kommentar kräver detta att du separerar dina källfiler från dina utdatafiler, eftersom det inte kan skriva ut en JS-fil på samma plats som en JS-källfil.
Alternativ 2: constants.d.ts deklarationsfil
Givet din källfil som ser ut så här:
// constants.js
export const MY_CONST_1 = 1;
Du kan skriva en constants.d.ts-fil som ser ut så här:
// constants.d.ts
export const MY_CONST_1: number;
Där du gick fel i dina tidigare försök är användningen av deklarationen module, som används för att deklarera typer för externa moduler (som från node_modules). I det här fallet räcker det med att placera filen constants.d.ts i samma katalog som constants.js och använda export, vilket kommer att tala om för TS att det är en JS-modul som exporterar det värdet:
import { MY_CONST_1 } from "./constants";
import * as constants from "./constants";
Något viktigt att ha i åtanke är att .d.ts-filen inte kontrolleras mot .js-filen för att säkerställa att den faktiskt är korrekt, det är upp till dig. Så om du gör en ändring i .js-filen måste du se till att uppdatera .d.ts-filen på ett korrekt sätt. Ett kompileringsfel eller avsaknaden av ett kompileringsfel betyder inte att det är korrekt eller inte. Detta är en av anledningarna till att allowJs finns, eftersom det undviker sådana läckor.
Svar #2
export const MyConst =1;
Eller
export class MyGroup {
static MyConst: number
}
Generellt håll dig borta från moduler eftersom det inte är kompatibelt med betydelsen av moduler i inports. Använd istället "namespace" som är mycket likt en klass med statiska medlemmar. Det betyder att du förmodligen skulle kunna göra (på telefon och kan inte prova det):
export namespace MyNamespace {
export const MyConst = 1;
}
Men försök till sist undvika att linda in saker i extra namnrymder och klasser osv eftersom importsyntaxen är modulen. Det gör också din kod möjlig att trädskaffa.
