ecmascript 6 - Vad händer om tsconfig 'targets' och 'libs' blandas mellan beroenden för TypeScript-projekt?


Jag bygger en Electron-app som importerar ett modul som heter foo som importerar ett modul som heter bar. Jag underhåller alla tre projekten.

Historiskt sett (men utan någon anledning) har alla tre projekten olika värden för target och lib i deras tsconfig.json.

Electron-app tsconfig.json:

"target": "es5",
"lib": ["es2017", "es2016", "es2015", "dom"]

node_modules/foo tsconfig.json:

"target": "es2021",
"lib": ["es2019", "es2016", "es2015"]

node_modules/bar tsconfig.json:

"target": "es2017",
"lib": ["es2015"]

Fråga: Givet ett TypeScript-projekt, vilken effekt har dess target- och lib-värden på transpilationen av dess filer och på transpilationen av filer i andra projekt som beror på det? Vilka typer av problem kan uppstå med blandade värden mellan en beroende och dess beroenden?

Här är ett konkret exempel som du kan använda för illustrativa ändamål: Kan jag ställa in node_modules/bar för att rikta in "es2022" och fortfarande använda det i Electron-projektet som riktar in sig på "es6"?

Förresten: Är det fördelaktigt att lista fler poster i lib?

Svar #1

target-inställningen bestämmer hur JS språkkonstruktioner (inte standard JS-API:er) nedgraderats. Dvs. syntaktiskt socker från nyare JS-språkstandarder kan nedgraderas, men generellt kommer TypeScript-kompilatorn inte/kan inte nedgradera användningar av JS-API:er som inte finns i äldre ECMAScript-standarder (t.ex. Promise.all, Array.prototype.includes).

lib-inställningen bestämmer vilken version av standard-JS API:er/inbyggda bibliotek (såsom DOM) som förväntas vara tillgängliga i den miljö där koden körs. Det vill säga, JS API:er som finns i den valda standarden kommer att få sina typningar tillgängliga, och användningar av de som inte är tillgängliga bör utlösa kompilatorvarningar.

Observera: du bör inte behöva specificera flera ES-bibliotek samtidigt. Att bara specificera det nyaste du förväntar dig kunna använda bör räcka, tillsammans med eventuella önskade underavsnitt från nyare versioner (t.ex. es2015, es2017.String). Genom att lista flera talar du om för TS-kompilatorn att hämta typdefinitioner för flera JS API-versioner. Jag kan inte komma på något dåligt som skulle kunna hända av det, men jag kan inte heller komma på något bra som skulle kunna hända av det, och jag skulle hellre satsa pengar på att någon kan komma på något dåligt (till skillnad från bra) som skulle kunna hända.

Varje projekt/paket kompileras från TS till JS på egen hand. När ett projekt/paket kompileras sker ingen kompilering av beroenden (som kompileras separat), och TS-kompilatorn använder inställningarna i det projektets/paketets tsconfig.json för att kompilera det.

Här är några konsekvenser:

  • Ett projekt bör inte förvänta sig att saker bara fungerar om det är beroende av ett annat paket som genererade JS för ett nyare target än det som det valde

    • Det vill säga, beroendet kan använda språkkonstruktioner som inte behöver nedgraderas för target som det valde, men som skulle ha behövt nedgraderas ytterligare för ett beroende paket som använder en lägre target.
  • Ett projekt bör inte förvänta sig att saker bara fungerar om det beror på ett annat paket som använder nyare libs (d.v.s. nyare standard JS API:er) än de som det valde.

    • Det vill säga, beroendet kan förvänta sig att köras på en miljö som är nyare än den som den beroende förväntas köras på.

I båda fallen skulle problemet tekniskt sett vara ett problem för den beroende, och skulle observeras som att beroendet inte fungerar som förväntat eller ger fel i vissa äldre miljöer som den beroende avsåg att stödja. Det finns två sätt att undvika/mildra att denna situation uppstår:

  • På den beroende sidan (den som använder beroenden):

    • Om möjligt, lägg till polyfills för JS-API:er som beroenden förväntar sig att kunna använda men som den beroende inte förväntar sig ska finnas i distributionsmiljön.
    • Verktyg kan infogas i projektets byggsystem som bundlar beroenden med projektets egen kod och gör en annan runda av nedgraderingar (utöver den runda som TS-kompilatorn gör för varje projekt separat enligt varje projekts olika tsconfig-inställningar). Ex. med någon WebPack + Babel-inställning.
  • På bibliotekets författarsida:

    • Många populära bibliotek som använder TS-källkod väljer konservativa värden för target och lib, såsom ES6 (ES2015), vilket är mycket väl stöds vid tiden för denna skrivning. De gör detta för att öka chansen att deras bibliotek kan vara kompatibelt med en beroende. Du kan tacka dem för det.

Dvs. Foos användning av Bar är okej (både target och lib är högre i Foo än i Bar), men Electron-appens användning av Foo är det inte.

Jag tror inte att TS-kompilatorn kommer att varna dig om du gör misstag när det gäller detta, eftersom tsconfigs vanligtvis inte distribueras med paket efter kompilering. Dvs. TS-kompilatorn har inget sätt att få den informationen om paketet. Men som redan diskuterats bör du inte göra det. Det finns förmodligen utrymme för förbättringar inom detta område i TS-verktygen och ekosystemet, men av någon anledning ses det nuvarande tillståndet som normalt/accepterat - kanske för att många populära bibliotek gör en ansträngning för att undvika språkkoncept och JS-API:er som ännu inte har särskilt bredt stöd.