Extract type resolves type reference dependency using typescript compiler api

Viewed 212

I have two files. One is in named type.

export type ExternalType = {
  type: 'external'
}

and another is

import { ExternalType } from './type'
    
interface IA {
  (): number
}
    
interface IB {
  type: 'b'
}

interface IC extends IB {
  type: 'c'
}
    
type AliasedType = {
  type: 'aliased'
}
  
type Check = {
  type: 'a'
  funcInterface: IA
  normalInterface: IB
  inheritedInterface: IC
  external: ExternalType
  aliased: AliasedType
}
    
type DummyType = {
  id: string
  type: 'dummy'
}

I want to extract Check type above specifying type name 'Check', and to get output the type form is followed by either.

a) Dependency all type reference nodes are replaced resolved builtin typescript type.

type Check = {
  type: 'a'
  funcInterface: () => number // or expression similar to Function type
  normalInterface: {
    type: 'b'
  }
  inheritedInterface: {
    type: 'b'
    type: 'c'
  }
  external: {
    type: 'external'
  }
  aliased: {
    type: 'aliased'
  }
}

or

b) extract all depended types and integrate to one file

type ExternalType = {
  type: 'external'
}

interface IA {
  (): number
}
    
interface IB {
  type: 'b'
}

interface IC extends IB {
  type: 'c'
}    

type AliasedType = {
  type: 'aliased'
}
    
type Check = {
  type: 'a'
  funcInterface: IA
  normalInterface: IB
  inheritedInterface: IC
  external: ExternalType
  aliased: AliasedType
}
    

The followed by partial code I wrote extracts Check type but, don't resolve dependency types.

function generateCodeFromAst(ast: ts.Node) {
  const resultFile = ts.createSourceFile(
    'dummy.ts',
    '',
    ts.ScriptTarget.Latest,
    /* setParentNodes */ false,
    ts.ScriptKind.TS,
  );
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
  const generatedCode = printer.printNode(
    ts.EmitHint.Unspecified,
    ast,
    resultFile,
  );
  return generatedCode;
}

// some omitted code 
// visit 
      if (node.name.text === symbol) {
        const t = checker.getTypeAtLocation(node);
        // NOTE: https://stackoverflow.com/questions/67423762/typescript-compilerapi-how-to-get-expanded-type-ast
        const ast = checker.typeToTypeNode(
          t,
          undefined,
          ts.NodeBuilderFlags.NoTruncation | ts.NodeBuilderFlags.InTypeAlias,
        );
        console.log(generateCodeFromAst(ast!))

This outputs like

{ type: "a"; funcInterface: IA; normalInterface: IB; inheritedInterface: IC; external: ExternalType; aliased: AliasedType; }

Ultimately, I want to insert the Check type node AST to another AST with resolved type dependencies either way above. If we don't have dependencies type, the code works.

ts.factory.createTypeLiteralNode([
  ts.factory.createPropertySignature(
     undefined,
     ts.factory.createIdentifier('check'),
     undefined,
     CheckTypeAST,
  ),
]),

Is it possible?

1 Answers

Finally I use ts-morph and extract all type and interface then, picking need type is realized. These code achieves my goal for my work though possibly may cause error like circular dependencies or complex Generic type.

Related