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;
}

Relaterede artikler