7

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.

1
  • 1
    Can you clarify your use case? It may be that someone could provide an answer that doesn't answer your exact question, but does solve your problem. What I mean by that is, maybe there's a way to do whatever you need to do, but it just can't be done with this exact approach. Commented Jul 26, 2021 at 15:06

2 Answers 2

8

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I stumbled on basically the same solution, but I didn't catch the TypeFormatFlags bit. Thanks for that. That said, beware the union types. If you call node.getType().getUnionTypes().length and get a positive number, you could be missing several properties. (In my particular use case, generating a stub class from a type, union types are a Bad Thing. But they might not be for yours.)
1

I created a CLI tool, ts-simplify, based off of @sparkofreason's answer. It's a compiler, which outputs the simplified primitive types. For example:

npx ts-simplify source-code.ts output-types.ts

This would output a file with the desired output:

export type NameOnlyAliased = {
    name: string;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.