考虑以下界面:
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"
。
答案 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
与我的问题相同。