javascript - ES2015-modulsyntax föredras framför egna TypeScript-moduler och namnrymder @typescript-eslint/no-namespace
Jag får följande felmeddelande när jag kör npm start:
ES2015-modulsyntax föredras framför egna TypeScript-moduler och namnrymder @typescript-eslint/no-namespace
namespace InternalThings {...}
Jag försökte forska om detta men det är väldigt förvirrande.
Varför händer detta? Hur åtgärdar man det?
Jag försökte sätta några flaggor på min tsconfig.json men hittills utan framgång;
Svar #1
Detta är ett lint-fel, orsakat av denna lint-regel: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-namespace.mdx
Om du tycker att regeln är användbar och vill behålla den, då behöver du ändra din kod för att använda import och export istället för namespace. Se dokumentationen för regeln för vad som räknas som en åtgärd.
Om du gillar regeln men vill inaktivera regeln för denna rad, lägg till följande precis ovanför den:
// eslint-disable-next-line @typescript-eslint/no-namespace
Om du inte gillar regeln och vill inaktivera den helt, redigera då din .eslintrc-fil för att ha följande rad:
rules: {
"@typescript-eslint/no-namespace": "off"
}
Svar #2
För att åtgärda detta fel, istället för:
export namespace InternalThings {
export function myFunction() {
}
export class MyClass {
}
}
import { InternalThings } from './internal-things';
InternalThings.myFunction();
du exponerar alla medlemmar i namnrymden direkt:
export function myFunction() {
}
export class MyClass {
}
och du importerar det så här:
import * as InternalThings from './internal-things';
InternalThings.myFunction();
Huvudidén är att användare av din modul bara kan importera det de vill, eller namnge din modul annorlunda:
import * as CustomModuleName from './internal-things';
CustomModuleName.myFunction();
import { MyClass } from './internal-things';
let field = new MyClass();
Svar #3
Fixa Lint-fel samtidigt som samma API bevaras
Om du vill hantera lint-felet utan att bryta några befintliga implementationer kan du göra följande, men du bör verkligen titta på svaret ovan innan du förbinder dig till detta: https://stackoverflow.com/a/63574739/349659
Innan
Implementationexport namespace Container {
export function someCall() { }
export function anotherCall() { }
}
Consumerimport { Container } from './Container'
Container.someCall()
Container.anotherCall()
Efter
Alternativ 1
// These are essentially private
function someCall() { }
function anotherCall() { }
// We expose them here
// This feels like a step towards CommonJS, but is valid ES Module code
export const Container = {
someCall,
anotherCall,
}
Alternativ 2
Du kan också definiera och kapsla in funktionsanropen direkt i objektet på följande sätt:
export const Container = {
someCall() {},
anotherCall() {},
}
Sammanfattningsvis
Om du har en stor kodbas och vill "snabbt" tillfredsställa din linter, kan du göra en refaktorering som ovan. Se till att ta hänsyn till detta svar https://stackoverflow.com/a/63574739/349659 och resonemanget bakom det.
I slutet av dagen är den snabbaste lösningen som inte kräver någon kodändring helt enkelt att stänga av denna lintningsregel som nämnts i detta svar: https://stackoverflow.com/a/58271234/349659
Om du börjar från början och stöter på detta problem skulle jag överväga att använda den moderna implementeringen som lintverktyget antyder, men du kanske märker att du gillar namnrymder och helt enkelt vill ha dem också. Om du är en del av ett team kan du vilja få deras feedback först och följa en teamstandard.
Kantfall & Överväganden
Ett fall jag har stött på är att ha flera namnrymder i samma fil. I detta scenario kan du då få namnkonflikter efter att ha tagit bort namnrymden.
Exempel
Innan
export namespace Container {
export function someCall() { }
export function anotherCall() { }
}
export namespace AnotherContainer {
export function someCall() { }
export function anotherCall() { }
}
Efter
Omkallning av kollisioner
I det här scenariot, när du tar bort namnområdet, kan du byta namn på kollisionerna samtidigt som du behåller exporten på följande sätt:
function containerSomeCall() { }
function containerAnotherCall() { }
export const Container = {
someCall: containerSomeCall,
anotherCall: containerAnotherCall,
}
function anotherContainerSomeCall() { }
function anotherContainerAnotherCall() { }
export const AnotherContainer = {
someCall: anotherContainerSomeCall,
anotherCall: anotherContainerAnotherCall,
}
Att koppla bort koden
Ett annat alternativ är att separera dem till sina egna filer. Om du dock vill behålla exporterna från den ursprungliga filen måste du importera och exponera dem, vilket kan tyckas vara duplicering, men kan vara ett mellanliggande steg mot en större refaktorering (senare uppdatera imports för att peka på de nya filerna). Detta gör det också möjligt att börja skriva mer modern ESM-kod om du vill, samtidigt som du vidarebefordrar nya exporter genom den gamla modulen.
Container.tsfunction someCall() { }
function anotherCall() { }
export const Container = {
someCall,
anotherCall,
}
AnotherContainer.tsfunction someCall() { }
function anotherCall() { }
export const AnotherContainer = {
someCall,
anotherCall,
}
OriginalFile.tsexport * from './Container'
export * from './AnotherContainer'
Vi kan proxy de nya ESM-modulerna genom den gamla ursprungliga modulen.
