You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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类型,配置简单:

  1. 安装依赖:
npm install react-docgen-typescript --save-dev
  1. 示例代码:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:02:03