typescripttypescript-compiler-api

TypeScript Compiler API: get type structure


Is there an API method to get the "bottomed out" type information from the TypeScript compiler? Example:

interface User {
  id: number
  name: string
}

type NameOnly = Pick<User, 'name'>

type NameOnlyAliased = NameOnly

In VSCode, if I hover over NameOnlyAliased, it shows:

type NameOnlyAliased = {
    name: string;
}

My question is if there is a function in the compiler API (or other simple way without applying the semantics of aliases, Pick, etc.) to get the info on the right-hand side of the = above, preferably as data (not just a string), something like:

{
  NameAliasedOnly: {
    properties: {
      name: {
         type: 'string'
      }
    }
  }
}

The use-case is to generate code to create fast-check arbitraries from type definitions (if that already exists, then fantastic). I've played around a bit with using ts-json-schema-generator for this purpose, but there are some type definitions it doesn't handle.


Solution

  • I've found a solution. It doesn't use the TypeScript compiler API, directly, but rather the excellent ts-morph library, a wrapper for the compiler API which simplifies many tasks. Here's some example code, where the test.ts file contains the example code from my question above.

    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
              ),
          ])
      )
    }
    

    Executing this script gives output [ [ 'name', 'string' ] ], as desired. For more complex types you can navigate into the type hierarchy.