Ambientdeklaration med en importerad typ i TypeScript
Jag har en deklarationsfil i mitt TypeScript-projekt som följer:
// myapp.d.ts
declare namespace MyApp {
interface MyThing {
prop1: string
prop2: number
}
}
Detta fungerar utmärkt och jag kan använda detta namespace var som helst i mitt projekt utan att behöva importera det.
Jag behöver nu importera en typ från ett tredjepartsmodul och använda den i min omgivande deklaration:
// myapp.d.ts
import {SomeType} from 'module'
declare namespace MyApp {
interface MyThing {
prop1: string
prop2: number
prop3: SomeType
}
}
Kompilatorn klagar nu på att den inte kan hitta namespace 'MyApp', förmodligen eftersom importen hindrar det från att vara ambient.
Finns det något enkelt sätt att behålla deklarationens omgivande karaktär samtidigt som man använder tredjepartstyper?
Svar #1
Ja, det finns ett sätt. Det har blivit lättare i TypeScript 2.9 genom att använda import() av en typ, men det är också möjligt i tidigare versioner av TypeScript.
Följande fil är ett script. Saker som deklareras i ett script läggs till i globalt omfång. Det är därför du kan använda MyApp.MyThing utan att importera det.
// myapp.d.ts
declare namespace MyApp {
interface MyThing {
prop1: string;
prop2: number;
}
}
Skript är begränsade på det sättet att de inte kan importera något; när du lägger till en import blir skriptet ett modul. Jag tycker att det är märkligt, minst sagt, men det är som det är. Det som är viktigt är att saker som definieras i en modul är begränsade till den modulen, och läggs inte till i det globala omfånget.
Men moduler kan också lägga till deklarationer i den globala omfattningen, genom att lägga dem inne i global:
// myapp.d.ts
import {SomeType} from 'module';
declare global {
namespace MyApp {
interface MyThing {
prop1: string;
prop2: number;
prop3: SomeType;
}
}
}
Den här filen är en modul, men den lägger till en deklaration av MyApp.MyThing i det globala området, så du kan fortfarande använda MyApp.MyThing i annan TypeScript-kod utan att importera den.
Observera att användningen av .d.ts-tillägget inte har något att göra med att du kan komma åt gränssnittet utan att importera det. Båda ovanstående filer skulle kunna ha varit .ts-filer och skulle fortfarande bete sig precis på samma sätt.
Svar #2
Sedan TS 2.9 är detta möjligt med import():
// myapp.d.ts
declare type SomeType = import('module').SomeType;
declare type SomeDefaultType = import('module-with-default-export').default;
declare namespace MyApp {
interface MyThing {
prop1: string;
prop2: number;
prop3: SomeType | SomeDefaultType;
}
}
