visual studio code - Hur kan jag se det fullständiga utökade kontraktet för en Typescript-typ?
Om jag har en samling av typer som ser lite ut så här:
type ValidValues = string | number | null
type ValidTypes = "text" | "time" | "unknown"
type Decorated = {
name?: string | null
type?: ValidTypes
value?: ValidValues
title: string
start: number
}
type Injected = {
extras: object
}
// overriding the types from Decorated
type Text = Decorated & Injected & {
name: string
type: "text"
value: string
}
Min faktiska kod har mer som pågår, men detta visar huvudidén. Jag vill inte behöva lita på mig själv att få relationerna mellan typerna exakt rätt. Jag vill att verktyg ska visa mig vad typdefinitionen för Text "utvärderas" till, efter all typalgebra.
Så för exemplet ovan hoppas jag att fälten som specificeras i Text kommer att åsidosätta de tidigare deklarationerna som gjorts i Decorated-typen, och resultatet av en hypotetisk verktygstips bör visa mig något i stil med detta:
{
name: string
type: "text"
value: string
title: string
start: number
extras: object
}
Finns det något bekvämt sätt att få denna information?
Svar #1
Den snabba informationen för en typ som visas med IntelliSense lämnar ofta något att önska; man får i allmänhet en enda representation för en viss typ, vilket kan visa sig vara för kortfattat eller till och med för utförligt för dina ändamål. Det finns några förslag för att göra det mer flexibelt (t.ex. microsoft/TypeScript#25784 och microsoft/TypeScript#28508) så att användare skulle kunna expandera/komprimera typdefinitioner i sina IDE:er. Men jag vet inte om de kommer att åtgärdas inom den närmaste eller ens avlägsna framtiden, så låt oss inte vänta på det.
Här är en typalias som jag ibland använder för att försöka utvidga en typ på det sätt du pratar om:
// expands object types one level deep
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
// expands object types recursively
type ExpandRecursively<T> = T extends object
? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
: T;
Dessa använder villkorlig typinferens för att "kopiera" en typ T till en ny typvariabel O och sedan en identitetsliknande mappad typ som går igenom de kopierade typens egenskaper.
Den villkorliga typinferensen är konceptuellt en no-op, men den används för att distribuera unionstyper och för att tvinga kompilatorn att utvärdera den "sanna" grenen av villkoret (om du omdefinierar Expand<T> utan den, kommer ibland kompilatorn bara att outputa den mappade typen {[K in keyof RelevantType]: RelevantType[K]}, vilket inte är vad du vill se).
Skillnaden mellan Expand och ExpandRecursively är om det bara ska mata ut egenskapstyperna som de är (Expand), eller om det ska expandera egenskapstyperna (ExpandRecursively). Det är till hjälp i det rekursiva fallet att inte försöka borra ner i primitiva typer, så därför inkluderas villkoret T extends object.
Okej, låt oss se vad som händer när vi använder det på din typ. Vi behöver inte ExpandRecursively i ditt fall, men vi skulle kunna använda det... det ger samma resultat:
type ExpandedText = Expand<Text>;
vilket, när vi hovrar över det i IDE:n (TypeScript Playground och VSCode i alla fall), visas som:
/* type ExpandedText = {
name: string;
type: "text";
value: string;
title: string;
start: number;
extras: object;
} */
som du ville.
Länk till kod
Svar #2
Bara kompletterar jcalz:s svar med versioner som fungerar med funktioner.
De modifierade hjälparna:
export type Expand<T> = T extends (...args: infer A) => infer R
? (...args: Expand<A>) => Expand<R>
: T extends infer O
? { [K in keyof O]: O[K] }
: never;
export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
: T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T;
För att testa lägger jag till en subobject-nyckel till Text-typ och lägger till ett funktionsgränssnitt:
type Text = Decorated &
Injected & {
name: string;
type: "text";
value: string;
subobject: Injected;
};
interface SomeFunction {
(...args: Text[]): Injected & { error: boolean };
}
Detta ger:
Objekt fungerar fortfarande bra:
Svar #3
Jag tyckte att denna VS Code-tillägg fungerade perfekt för detta:
Försköna TypeScript: Bättre typförhandsvisningar
Det visar även djupt nästlade typer vid hovring.





