使用Typescript编译器API获取接口字段的类型信息

时间:2018-09-26 15:13:46

标签: typescript abstract-syntax-tree typescript-compiler-api

考虑以下界面:

interface X { 
  x: string 
}

我正在尝试使用Typescript编译器API获取属性x的类型。这是我到目前为止的内容:

import {
  PropertySignature,
  createSourceFile,
  ScriptTarget,
  ScriptKind,
  SyntaxKind,
  InterfaceDeclaration,
  Identifier,
} from 'typescript'

describe('Compiler test', () => {
  it('should be able to find type information about X.x', () => {
    const sourceText = 'interface X { x: string }'
    const ast = createSourceFile('source.ts', sourceText, ScriptTarget.ES5, false, ScriptKind.TS)
    const interfaceX = ast
      .getChildAt(0)
      .getChildren()
      .find((child) => child.kind === SyntaxKind.InterfaceDeclaration) as InterfaceDeclaration
    const propX = interfaceX.members.find((member) => (member.name as Identifier).escapedText === 'x')
    console.log(JSON.stringify(propX, null, 2))
  })
})

现在propX节点的内容如下:

{
  "pos": 13,
  "end": 23,
  "flags": 0,
  "kind": 151,
  "name": {
    "pos": 13,
    "end": 15,
    "flags": 0,
    "escapedText": "x"
  },
  "type": {
    "pos": 16,
    "end": 23,
    "flags": 0,
    "kind": 137
  }
}

可以从中清楚地提取节点的名称,但是类型节点似乎没有任何有用的信息。

如何获取属性的类型信息?我需要的只是"string"

1 个答案:

答案 0 :(得分:0)

因此,方法是构建Program(需要CompilerHost来完成)并按照@MattMcCutchen的建议使用TypeChecker

CompilerHost(您不需要类实现,但我发现它更方便):

export const SAMPLE_FILE_NAME = 'sample.ts'

export class TestCompilerHost implements CompilerHost {
  constructor(private readonly code: string) {}
  fileExists = () => true
  getCanonicalFileName = () => SAMPLE_FILE_NAME
  getCurrentDirectory = () => ''
  getDefaultLibFileName = () => 'lib.d.ts'
  getDirectories = () => []
  getNewLine = () => '\n'
  readFile = () => null
  useCaseSensitiveFileNames = () => true
  writeFile = () => {}
  getSourceFile(filename: string): SourceFile {
    return createSourceFile(filename, this.code, ScriptTarget.ES5, true)
  }
}

构建一个Program

const config: CompilerOptions = {
  noResolve: true,
  target: ScriptTarget.ES5,
}
const sourceText = `interface X { x: string }`
const program = createProgram([SAMPLE_FILE_NAME], config, new TestCompilerHost(sourceText))

像问题中一样找到接口和属性(唯一的区别是访问SourceFile的方式):

const ast = program.getSourceFile(SAMPLE_FILE_NAME)
const interfaceX = ast
  .getChildAt(0)
  .getChildren()
  .find((child) => child.kind === SyntaxKind.InterfaceDeclaration) as InterfaceDeclaration
const propX = interfaceX.members.find((member) => (member.name as Identifier).escapedText === 'x')

最后得到的类型:

const typeChecker = program.getTypeChecker()
const type = typeChecker.getTypeAtLocation(propX.type)
const stringType typeChecker.typeToString(type)

propX与我的问题相同。