TypeScript Compiler API: hent typestruktur
Findes der en API-metode til at få information om typen, der er 'bottomed out', fra TypeScript-kompilatoren? Eksempel:
interface User {
id: number
name: string
}
type NameOnly = Pick<User, 'name'>
type NameOnlyAliased = NameOnly
I VSCode, hvis jeg holder musen over NameOnlyAliased, viser det:
type NameOnlyAliased = {
name: string;
}
Mit spørgsmål er, om der er en funktion i compiler-API'en (eller en anden simpel måde uden at anvende semantikken af aliaser, Pick, osv.) til at få informationen på højre side af = ovenfor, helst som data (ikke kun som en streng), noget i retning af:
{
NameAliasedOnly: {
properties: {
name: {
type: 'string'
}
}
}
}
Brugstilfældet er at generere kode til at oprette fast-check arbitraries ud fra typedefinitioner (hvis det allerede findes, så fantastisk). Jeg har leget lidt med at bruge ts-json-schema-generator til dette formål, men der er nogle typedefinitioner, som den ikke håndterer.
Svar #1
Jeg har fundet en løsning. Den bruger ikke TypeScript-kompilatorens API direkte, men derimod det fremragende ts-morph bibliotek, en wrapper til kompilator-API'en, som forenkler mange opgaver. Her er noget eksempel på kode, hvor test.ts filen indeholder eksempel-koden fra mit spørgsmål ovenfor.
import { Project, TypeFormatFlags } from 'ts-morph'
const project = new Project({
tsConfigFilePath: 'tsconfig.json',
skipAddingFilesFromTsConfig: true,
})
const file = 'test.ts'
project.addSourceFileAtPath(file)
const sourceFile = project.getSourceFile(file)
const typeAlias = sourceFile?.getTypeAlias('NameOnlyAliased')
if (typeAlias) {
console.log(
typeAlias
.getType()
.getProperties()
.map(p => [
p.getName(),
p
.getTypeAtLocation(typeAlias)
.getText(
undefined,
TypeFormatFlags.UseAliasDefinedOutsideCurrentScope
),
])
)
}
Udførelse af dette script giver output [ [ 'name', 'string' ] ], som ønsket. For mere komplekse typer kan du navigere ind i typehierarkiet.
Svar #2
Jeg har lavet et CLI-værktøj, ts-simplify, baseret på @sparkofreason's svar. Det er en compiler, som outputter de forenklede primitive typer. For eksempel:
npx ts-simplify source-code.ts output-types.ts
Dette ville generere en fil med det ønskede output:
export type NameOnlyAliased = {
name: string;
}
