如何通过TypeScript Compiler API获取JSX组件属性的定义类型
问题描述
现有React组件代码如下:
import type {ReactNode} from 'react' import React from 'react' type Props = { title: ReactNode } export const Comp: React.FC<Props> = ({title}) => { return <div>{title}</div> } export const A = () => { return <Comp title="smth" /> }
需要通过TypeScript Compiler API获取Comp组件title属性定义时的类型(即ReactNode),但当前尝试的代码输出的是属性值"smth"的类型string,不符合需求。
当前尝试的代码问题在于:typeChecker.getTypeAtLocation(attr.name)获取的是JSX属性名称的类型(字符串字面量),而非组件Props中该属性的定义类型。
解决方案:TypeScript Compiler API 正确实现
核心思路是从JSX元素对应的组件标识符入手,追踪到组件的Props类型定义,再提取目标属性的类型:
import { readFileSync } from 'node:fs' import ts from 'typescript' function checkJSXProperties(typeChecker: ts.TypeChecker) { const visitor: ts.Visitor = (node) => { if (ts.isJsxSelfClosingElement(node)) { // 获取JSX组件的标识符(比如<Comp />里的Comp) const componentIdentifier = node.tagName if (!ts.isIdentifier(componentIdentifier)) return node // 获取组件的符号信息 const componentSymbol = typeChecker.getSymbolAtLocation(componentIdentifier) if (!componentSymbol) return node // 获取组件的类型(React.FC<Props>) const componentType = typeChecker.getTypeOfSymbolAtLocation(componentSymbol, componentIdentifier) // 提取React.FC的泛型参数(即Props类型) const propsType = componentType.getTypeArguments()[0] if (!propsType) return node // 遍历JSX属性,匹配Props里的对应类型 node.attributes.properties.forEach(attr => { if (!ts.isJsxAttribute(attr)) return const propName = attr.name.getText() // 从Props类型中获取对应属性的符号 const propSymbol = propsType.getProperty(propName) if (!propSymbol) return // 获取属性的定义类型 const propType = typeChecker.getTypeOfSymbolAtLocation(propSymbol, componentIdentifier) // 将类型转换为可读的字符串 const typeText = typeChecker.typeToString(propType) console.log(`Property '${propName}' is defined as type: '${typeText}'`) }) } return ts.visitEachChild(node, visitor, undefined) } return visitor } const filePath = './src/scripts/index.tsx' // 创建Program(必须基于整个项目,transpileModule无法获取完整类型信息) const program = ts.createProgram([filePath], { noEmit: true, jsx: ts.JsxEmit.React, module: ts.ModuleKind.CommonJS, }) const typeChecker = program.getTypeChecker() const sourceFile = program.getSourceFile(filePath)! // 遍历AST节点 ts.visitNode(sourceFile, checkJSXProperties(typeChecker))
关键说明:
- 必须使用
ts.createProgram而非ts.transpileModule:transpileModule是单文件转译,无法获取跨文件/模块的类型信息(比如React.FC的定义) - 步骤拆解:组件标识符 → 组件符号 → 组件类型 → 泛型Props类型 → 属性符号 → 属性定义类型
typeChecker.typeToString用于将TS内部类型对象转换为可读的字符串(比如ReactNode)
运行上述代码后,会输出:
Property 'title' is defined as type: 'ReactNode'
其他可选工具
如果不想直接操作TypeScript Compiler API,可以使用react-docgen-typescript,它专门用于解析React组件的Props类型,配置简单:
- 安装依赖:
npm install react-docgen-typescript --save-dev
- 示例代码:
import { parse } from 'react-docgen-typescript' const filePath = './src/scripts/index.tsx' const components = parse(filePath) const compComponent = components.find(c => c.displayName === 'Comp') if (compComponent) { const titleProp = compComponent.props.title console.log(`Property 'title' is defined as type: '${titleProp.type.name}'`) }
输出同样会得到ReactNode。
内容的提问来源于stack exchange,提问作者Volok
相关产品推荐
相关产品推荐

