typescript - Hur skapar man en typ som ger en punktnotation av nästlade klassattribut som strängliteraler?
Detta är relaterat till AWS SDK, som har flera klienter, där varje av dem har namnrymder med egenskaper.
Detta bibliotek exporterar AWS, som har flera klienter, t.ex. DynamoDB och ACM. DynamoDB har en egenskap som heter DocumentClient. ACM har en egenskap som heter CertificateBody.
class _DocumentClient {}
namespace _DocumentClient {}
// DynamoDB that is imported in the AWS module (see below)
declare class _DynamoDB {}
declare namespace _DynamoDB {
export import DocumentClient = _DocumentClient;
}
// ACM client that is imported in the AWS module (see below)
declare class _ACM {}
declare namespace _ACM {
export type CertificateBody = string;
}
// AWS module (mimicking)
// The original library (as linked above) exports a lot more clients...
namespace AWS {
export import ACM = _ACM;
export import DynamoDB = _DynamoDB;
}
Jag försöker skapa en typ som ger en union av strängliteraler som "DynamoDB.DocumentClient" | "ACM.CertificateBody".
Jag har försökt få listan över alla egenskaper för varje klient, men det verkar vara en omöjlig uppgift, för att inte tala om att lägga till en klient och egenskap med en punktnotation.
Jag lyckades bara få prototype strängliteral istället för de önskade DocumentClient och CertificateBody strängliteralerna.
// this works - ("ADM" | "DynamoDB")
type ClientName = keyof typeof AWS;
// shouldn't this yield "DocumentClient" | "CertificateBody"? Using this type only means I can use "prototype" :/
type NestedClientName<C extends ClientName> = keyof typeof AWS[C];
// I want to be able to get a type with a union of string literals like `"ACM.CertificateBody" | "DynamoDB.DocumentClient"
type NestedClientFullName<C extends ClientName, NC extends NestedClientName<C>> = `${C}.${NC}`;
Tyvärr ger varken NestedClientName (och som en konsekvens, NestedClientFullName) rättvisa resultat.
Här är en direktlänk till hela filen på GitHub för kontext, för att visa den ursprungliga aws-sdk-filen. Jag har återskapat den i båda exemplen ovan och på lekplatsen nedan.
Lekplats
Svar #1
Enligt kodexemplet har ACM faktiskt ingen egenskap som heter CertificateBody, så det du frågar efter är omöjligt, åtminstone för de delar av din uppgift som involverar exporterade typer.
I TypeScript kan namespace fungera både som värden som finns vid körning och innehåller egenskaper, och som namnrymder för typer som endast finns i TypeScript-kod. När du export ett värde (som en const eller en function) från ett namespace blir det en egenskap på namespace-värdet. När du exporterar en typ (som ett interface eller en type) från ett namespace gör det inte det.
Om du har ett namnrymd som heter Foo, kommer typeof Foo att ge dig typen av värdet value som heter Foo, vilket innehåller alla exporterade värden som egenskapsnycklar. Det kommer inte att ge dig någon åtkomst till typenamnrymden som heter Foo, eller något sätt att lista de typer som finns där. Faktum är att det inte finns något sätt att uppräkna typer i TypeScript:
declare namespace Foo {
export const v: number;
export type T = number;
}
type K = keyof typeof Foo;
// type K = "v"
Bara för att understryka idén att typen och värdet är olika: om du endast exporterar typer och inte värden från ett namnrum, kommer det inte ens att finnas ett värde motsvarande namnrymden:
declare namespace Bar {
export const v: number;
}
const okay = Bar; // okay
declare namespace Baz {
export type T = number;
}
const oops = Baz; // error
I det ovanstående finns typeof Bar som en objekttyp med en number-värderad v-egenskap, men typeof Baz finns inte alls. Det finns inget värde som heter Baz vars type du kan få. Baz är endast ett namnrymd för typer.
Så, ACM har ingen egenskap som heter CertificateBody. Istället har namespace ACM en typ som kallas CertificateBody. Typen kan refereras direkt i TypeScript som ACM.CertificateBody, men det finns inget sätt att komma åt den programmatisk, och absolut inte som en strängliteraltyp som "CertificateBody". Tyvärr är det du försöker göra omöjligt.
Lekplatslänk till kod
