diff --git a/.changeset/tidy-beans-smile.md b/.changeset/tidy-beans-smile.md
new file mode 100644
index 00000000000..627d1d9ef34
--- /dev/null
+++ b/.changeset/tidy-beans-smile.md
@@ -0,0 +1,5 @@
+---
+'react-docgen': patch
+---
+
+Support Babel 8 dependency overrides for parsing and traversal, including TypeScript generic props, inherited interfaces, function types, and mapped types. Preserve Babel 7 compatibility.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3c81c218d60..22577fb3434 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,16 +15,33 @@ env:
jobs:
tests:
strategy:
+ fail-fast: false
matrix:
+ babel: ["7", "8"]
node: ["22.13.0", "24", "25", "26"]
os: ["ubuntu"]
+ exclude:
+ # Babel 8 requires Node.js 22.18.0 or newer on the 22.x line.
+ - babel: "8"
+ node: "22.13.0"
include:
+ - os: ubuntu
+ node: "22.18.0"
+ babel: "8"
- os: macos
node: "24"
+ babel: "7"
+ - os: macos
+ node: "24"
+ babel: "8"
+ - os: windows
+ node: "24"
+ babel: "7"
- os: windows
node: "24"
+ babel: "8"
- name: Tests (Node.js v${{ matrix.node }}, ${{ matrix.os }})
+ name: Tests (Babel ${{ matrix.babel }}, Node.js v${{ matrix.node }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}-latest
steps:
@@ -43,13 +60,21 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
+ # Compile against the declared Babel 7 types before testing each runtime.
+ - name: Build packages
+ run: pnpm build
+
+ - name: Install Babel 8 runtime
+ if: "${{ matrix.babel == '8' }}"
+ run: pnpm --filter react-docgen add --save-exact @babel/core@8.0.1 @babel/traverse@8.0.4 @babel/types@8.0.4
+
- name: Unit tests with coverage
if: "${{ matrix.node == env.NODE_VERSION }}"
- run: pnpm test -- --coverage
+ run: pnpm --filter react-docgen --filter @react-docgen/cli --parallel --no-bail test --coverage
- name: Unit tests
if: "${{ matrix.node != env.NODE_VERSION }}"
- run: pnpm test
+ run: pnpm --filter react-docgen --filter @react-docgen/cli --parallel --no-bail test
- name: Upload coverage
if: "${{ matrix.node == env.NODE_VERSION }}"
@@ -57,7 +82,7 @@ jobs:
uses: coverallsapp/github-action@8d6379e14d29928660c4ba802d8e85393440b329 # v2
with:
parallel: true
- flag-name: test-${{ matrix.os }}
+ flag-name: test-babel-${{ matrix.babel }}-${{ matrix.os }}
finish:
needs: tests
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7b34655b005..b81da617193 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -14,6 +14,26 @@ We actively welcome your pull requests.
4. Ensure the test suite passes.
5. Make sure your code lints and typechecks.
+## Babel compatibility tests
+
+CI runs all library and CLI tests separately with Babel 7 and Babel 8.
+Both runs build with the declared Babel 7 dependencies first. The Babel 8
+run then replaces the runtime dependencies, including those used by CLI
+subprocesses. This checks runtime compatibility, not compilation with Babel 8 types.
+
+To reproduce the Babel 8 run in a clean checkout:
+
+```sh
+pnpm install --frozen-lockfile
+pnpm build
+pnpm --filter react-docgen add --save-exact @babel/core@8.0.1 @babel/traverse@8.0.4 @babel/types@8.0.4
+pnpm --filter react-docgen --filter @react-docgen/cli --parallel --no-bail test --coverage
+```
+
+The install command changes `packages/react-docgen/package.json` and
+`pnpm-lock.yaml`. After testing, restore those two files and run
+`pnpm install --frozen-lockfile` to return to Babel 7.
+
## Issues
We use GitHub issues to track public bugs. Please ensure your description is
clear and has sufficient instructions to be able to reproduce the issue.
diff --git a/packages/react-docgen/src/__tests__/parserCompatibility-test.ts b/packages/react-docgen/src/__tests__/parserCompatibility-test.ts
new file mode 100644
index 00000000000..c086c0dd96a
--- /dev/null
+++ b/packages/react-docgen/src/__tests__/parserCompatibility-test.ts
@@ -0,0 +1,73 @@
+import { parse } from '../main.js';
+import { expect, test } from 'vitest';
+
+test('parses components', () => {
+ const result = parse('export function Button() { return ; }');
+
+ expect(result).toHaveLength(1);
+});
+
+test('parses TypeScript function props', () => {
+ const result = parse(
+ `export type MenuProps = {
+ onOpenChange?: (open: boolean) => void;
+ };
+
+ export function Menu(_props: MenuProps) {
+ return
;
+ }`,
+ { filename: 'index.tsx' },
+ );
+
+ expect(result[0]?.props?.onOpenChange?.tsType).toEqual({
+ name: 'signature',
+ type: 'function',
+ raw: '(open: boolean) => void',
+ signature: {
+ arguments: [
+ {
+ name: 'open',
+ type: { name: 'boolean' },
+ },
+ ],
+ return: { name: 'void' },
+ },
+ });
+});
+
+test('parses generic arrow functions in TypeScript files', () => {
+ const result = parse(
+ `import React from 'react';
+
+ export const mockDomain = (
+ entities: Record = {},
+ ) => ({ entities });
+
+ export function Button() {
+ return React.createElement('button');
+ }`,
+ { filename: 'store.ts' },
+ );
+
+ expect(result).toHaveLength(1);
+});
+
+test('parses mapped TypeScript props', () => {
+ const result = parse(
+ `export type StatusFiltersProps = {
+ statuses?: { readonly [Key in K]: number };
+ };
+
+ export function StatusFilters(
+ _props: StatusFiltersProps,
+ ) {
+ return ;
+ }`,
+ { filename: 'index.tsx' },
+ );
+
+ expect(result[0]?.props?.statuses?.tsType).toMatchObject({
+ name: 'signature',
+ type: 'object',
+ });
+});
diff --git a/packages/react-docgen/src/babelParser.ts b/packages/react-docgen/src/babelParser.ts
index 8c323c5a99c..0eaa6031ca1 100644
--- a/packages/react-docgen/src/babelParser.ts
+++ b/packages/react-docgen/src/babelParser.ts
@@ -1,34 +1,58 @@
import type { ParserOptions, TransformOptions } from '@babel/core';
-import { loadPartialConfig, parseSync } from '@babel/core';
+import * as babel from '@babel/core';
import type { File } from '@babel/types';
import { extname } from 'path';
const TYPESCRIPT_EXTS = new Set(['.cts', '.mts', '.ts', '.tsx']);
+const { parseSync, version } = babel;
+// Babel 7 exports this at runtime, but its DefinitelyTyped definitions omit it.
+const loadPartialConfigSync = (
+ babel as typeof babel & {
+ loadPartialConfigSync: typeof babel.loadPartialConfig;
+ }
+).loadPartialConfigSync;
+const IS_BABEL_8 = Number.parseInt(version, 10) >= 8;
function getDefaultPlugins(
options: TransformOptions,
): NonNullable {
- return [
- 'jsx',
- options.filename && TYPESCRIPT_EXTS.has(extname(options.filename))
- ? 'typescript'
- : 'flow',
+ const extension = options.filename ? extname(options.filename) : '';
+ const isTypeScript = TYPESCRIPT_EXTS.has(extension);
+ const plugins: NonNullable = [
+ ...(isTypeScript && extension !== '.tsx' ? [] : ['jsx' as const]),
+ isTypeScript ? 'typescript' : 'flow',
'asyncDoExpressions',
- 'decimal',
+ ];
+
+ if (!IS_BABEL_8) {
+ plugins.push('decimal');
+ }
+
+ plugins.push(
['decorators', { decoratorsBeforeExport: false }],
'decoratorAutoAccessors',
'destructuringPrivate',
'doExpressions',
'exportDefaultFrom',
'functionBind',
- 'importAssertions',
- 'moduleBlocks',
- 'partialApplication',
- ['pipelineOperator', { proposal: 'minimal' }],
- ['recordAndTuple', { syntaxType: 'bar' }],
- 'regexpUnicodeSets',
- 'throwExpressions',
- ];
+ );
+
+ if (!IS_BABEL_8) {
+ plugins.push('importAssertions');
+ }
+
+ plugins.push('moduleBlocks', 'partialApplication', [
+ 'pipelineOperator',
+ { proposal: IS_BABEL_8 ? 'fsharp' : 'minimal' },
+ ]);
+
+ if (!IS_BABEL_8) {
+ plugins.push(['recordAndTuple', { syntaxType: 'bar' }]);
+ }
+
+ plugins.push('regexpUnicodeSets', 'throwExpressions');
+
+ return plugins;
}
function buildPluginList(
@@ -42,7 +66,7 @@ function buildPluginList(
// Let's check if babel finds a config file for this source file
// If babel does find a config file we do not apply our defaults
- const partialConfig = loadPartialConfig(options);
+ const partialConfig = loadPartialConfigSync(options);
if (
plugins.length === 0 &&
diff --git a/packages/react-docgen/src/handlers/codeTypeHandler.ts b/packages/react-docgen/src/handlers/codeTypeHandler.ts
index 75310b4b3d8..c2898b7404f 100644
--- a/packages/react-docgen/src/handlers/codeTypeHandler.ts
+++ b/packages/react-docgen/src/handlers/codeTypeHandler.ts
@@ -55,7 +55,9 @@ function setPropDescriptor(
},
typeParams,
);
- } else if (!argument.has('typeParameters')) {
+ } else if (!(
+ 'typeParameters' in argument.node && argument.node.typeParameters
+ )) {
documentation.addComposes(id.node.name);
}
} else if (path.isObjectTypeProperty()) {
diff --git a/packages/react-docgen/src/handlers/displayNameHandler.ts b/packages/react-docgen/src/handlers/displayNameHandler.ts
index 09501b80eba..5f1394d2737 100644
--- a/packages/react-docgen/src/handlers/displayNameHandler.ts
+++ b/packages/react-docgen/src/handlers/displayNameHandler.ts
@@ -24,7 +24,7 @@ const displayNameHandler: Handler = function (
if (
(componentDefinition.isClassDeclaration() ||
componentDefinition.isFunctionDeclaration()) &&
- componentDefinition.has('id')
+ componentDefinition.node.id
) {
documentation.set(
'displayName',
diff --git a/packages/react-docgen/src/importer/makeFsImporter.ts b/packages/react-docgen/src/importer/makeFsImporter.ts
index bbd8b0cdf50..417690422f9 100644
--- a/packages/react-docgen/src/importer/makeFsImporter.ts
+++ b/packages/react-docgen/src/importer/makeFsImporter.ts
@@ -196,13 +196,14 @@ export default function makeFsImporter(
}
} else if (
declaration.hasNode() &&
- declaration.has('id') &&
+ 'id' in declaration.node &&
+ declaration.node.id &&
(declaration.get('id') as NodePath).isIdentifier({ name })
) {
// export function/class/type/interface/enum ...
state.resultPath = declaration;
- } else if (path.has('specifiers')) {
+ } else if (path.node.specifiers.length > 0) {
// export { ... } or export x from ... or export * as x from ...
for (const specifierPath of path.get('specifiers')) {
@@ -213,7 +214,7 @@ export default function makeFsImporter(
if (exported.isIdentifier({ name })) {
// export ... from ''
- if (path.has('source')) {
+ if (path.node.source) {
const local = specifierPath.isExportSpecifier()
? specifierPath.node.local.name
: 'default';
diff --git a/packages/react-docgen/src/utils/__tests__/getTypeParameters-test.ts b/packages/react-docgen/src/utils/__tests__/getTypeParameters-test.ts
index e715c21effd..62b40bac783 100644
--- a/packages/react-docgen/src/utils/__tests__/getTypeParameters-test.ts
+++ b/packages/react-docgen/src/utils/__tests__/getTypeParameters-test.ts
@@ -1,3 +1,4 @@
+import getTypeArguments from '../getTypeArguments.js';
import type {
TSTypeAliasDeclaration,
TSTypeParameterDeclaration,
@@ -20,9 +21,9 @@ describe('getTypeParameters', () => {
expect(
getTypeParameters(
path.get('typeParameters') as NodePath,
- path
- .get('typeAnnotation')
- .get('typeParameters') as NodePath,
+ getTypeArguments(
+ path.get('typeAnnotation'),
+ ) as NodePath,
null,
),
).toMatchSnapshot();
@@ -35,9 +36,9 @@ describe('getTypeParameters', () => {
expect(
getTypeParameters(
path.get('typeParameters') as NodePath,
- path
- .get('typeAnnotation')
- .get('typeParameters') as NodePath,
+ getTypeArguments(
+ path.get('typeAnnotation'),
+ ) as NodePath,
null,
),
).toMatchSnapshot();
diff --git a/packages/react-docgen/src/utils/getFlowType.ts b/packages/react-docgen/src/utils/getFlowType.ts
index 246fb64364e..2fe12a040d4 100644
--- a/packages/react-docgen/src/utils/getFlowType.ts
+++ b/packages/react-docgen/src/utils/getFlowType.ts
@@ -174,7 +174,11 @@ function handleGenericTypeAnnotation(
const resolvedPath =
(typeParams && typeParams[type.name]) || resolveToValue(path.get('id'));
- if (typeParameters.hasNode() && resolvedPath.has('typeParameters')) {
+ if (
+ typeParameters.hasNode() &&
+ 'typeParameters' in resolvedPath.node &&
+ resolvedPath.node.typeParameters
+ ) {
typeParams = getTypeParameters(
resolvedPath.get('typeParameters') as NodePath,
typeParameters,
@@ -195,7 +199,7 @@ function handleGenericTypeAnnotation(
);
}
- if (resolvedPath && resolvedPath.has('right')) {
+ if (resolvedPath && 'right' in resolvedPath.node && resolvedPath.node.right) {
type = getFlowTypeWithResolvedTypes(
resolvedPath.get('right') as NodePath,
typeParams,
diff --git a/packages/react-docgen/src/utils/getPropertyName.ts b/packages/react-docgen/src/utils/getPropertyName.ts
index 72e27dc3144..349b2226e20 100644
--- a/packages/react-docgen/src/utils/getPropertyName.ts
+++ b/packages/react-docgen/src/utils/getPropertyName.ts
@@ -42,7 +42,7 @@ export default function getPropertyName(
}
return null;
- } else if (propertyPath.has('computed')) {
+ } else if ('computed' in propertyPath.node && propertyPath.node.computed) {
const key = propertyPath.get('key') as NodePath;
// Try to resolve variables and member expressions
diff --git a/packages/react-docgen/src/utils/getTSType.ts b/packages/react-docgen/src/utils/getTSType.ts
index 91346f11915..3e2a4788816 100644
--- a/packages/react-docgen/src/utils/getTSType.ts
+++ b/packages/react-docgen/src/utils/getTSType.ts
@@ -1,3 +1,4 @@
+import getTypeArguments from './getTypeArguments.js';
import getPropertyName from './getPropertyName.js';
import printValue from './printValue.js';
import getTypeAnnotation from '../utils/getTypeAnnotation.js';
@@ -130,12 +131,15 @@ function handleTSTypeReference(
(typeParams && typeParams[type.name]) ||
resolveToValue(path.get('typeName'));
- const typeParameters = path.get('typeParameters');
+ const typeParameters = getTypeArguments(path);
const resolvedTypeParameters = resolvedPath.get('typeParameters') as NodePath<
TSTypeParameterDeclaration | null | undefined
>;
- if (typeParameters.hasNode() && resolvedTypeParameters.hasNode()) {
+ if (
+ typeParameters.isTSTypeParameterInstantiation() &&
+ resolvedTypeParameters.hasNode()
+ ) {
typeParams = getTypeParameters(
resolvedTypeParameters,
typeParameters,
@@ -157,7 +161,7 @@ function handleTSTypeReference(
if (resolvedTypeAnnotation.hasNode()) {
type = getTSTypeWithResolvedTypes(resolvedTypeAnnotation, typeParams);
- } else if (typeParameters.hasNode()) {
+ } else if (typeParameters.isTSTypeParameterInstantiation()) {
const params = typeParameters.get('params');
type = {
@@ -285,10 +289,12 @@ function handleTSMappedType(
path: NodePath,
typeParams: TypeParameters | null,
): ObjectSignatureType {
- const key = getTSTypeWithResolvedTypes(
- path.get('typeParameter').get('constraint') as NodePath,
- typeParams,
- );
+ const constraint = (
+ 'constraint' in path.node
+ ? path.get('constraint')
+ : path.get('typeParameter').get('constraint')
+ ) as NodePath;
+ const key = getTSTypeWithResolvedTypes(constraint, typeParams);
key.required = !path.node.optional;
@@ -321,8 +327,11 @@ function handleTSFunctionType(
typeParams: TypeParameters | null,
): TSFunctionSignatureType {
let returnType: TypeDescriptor | undefined;
+ const usesBabel8Fields = 'params' in path.node;
- const annotation = path.get('typeAnnotation');
+ const annotation = path.get(
+ usesBabel8Fields ? 'returnType' : 'typeAnnotation',
+ ) as NodePath;
if (annotation.hasNode()) {
returnType = getTSTypeWithResolvedTypes(annotation, typeParams);
@@ -338,7 +347,11 @@ function handleTSFunctionType(
},
};
- path.get('parameters').forEach((param) => {
+ const parameters = path.get(
+ usesBabel8Fields ? 'params' : 'parameters',
+ ) as Array>;
+
+ parameters.forEach((param) => {
const typeAnnotation = getTypeAnnotation(param);
const arg: FunctionArgumentType = {
@@ -399,7 +412,10 @@ function handleTSTypeQuery(
if (exprName.isIdentifier()) {
const resolvedPath = resolveToValue(path.get('exprName'));
- if (resolvedPath.has('typeAnnotation')) {
+ if (
+ 'typeAnnotation' in resolvedPath.node &&
+ resolvedPath.node.typeAnnotation
+ ) {
return getTSTypeWithResolvedTypes(
resolvedPath.get('typeAnnotation') as NodePath,
typeParams,
diff --git a/packages/react-docgen/src/utils/getTypeAnnotation.ts b/packages/react-docgen/src/utils/getTypeAnnotation.ts
index 3424700b150..42157111dc5 100644
--- a/packages/react-docgen/src/utils/getTypeAnnotation.ts
+++ b/packages/react-docgen/src/utils/getTypeAnnotation.ts
@@ -8,14 +8,21 @@ import type { FlowType, Node, TSType } from '@babel/types';
export default function getTypeAnnotation(
path: NodePath,
): NodePath | null {
- if (!path.has('typeAnnotation')) return null;
+ if (
+ !path.node ||
+ !('typeAnnotation' in path.node) ||
+ !path.node.typeAnnotation
+ )
+ return null;
let resultPath = path;
do {
resultPath = resultPath.get('typeAnnotation') as NodePath;
} while (
- resultPath.has('typeAnnotation') &&
+ resultPath.node &&
+ 'typeAnnotation' in resultPath.node &&
+ resultPath.node.typeAnnotation &&
!resultPath.isFlowType() &&
!resultPath.isTSType()
);
diff --git a/packages/react-docgen/src/utils/getTypeArguments.ts b/packages/react-docgen/src/utils/getTypeArguments.ts
new file mode 100644
index 00000000000..26315c9b1e7
--- /dev/null
+++ b/packages/react-docgen/src/utils/getTypeArguments.ts
@@ -0,0 +1,18 @@
+import type { NodePath } from '@babel/traverse';
+import type {
+ TSTypeParameterInstantiation,
+ TypeParameterInstantiation,
+} from '@babel/types';
+
+/** Reads type arguments from both Babel 7 and Babel 8 ASTs. */
+export default function getTypeArguments(
+ path: NodePath,
+): NodePath<
+ TSTypeParameterInstantiation | TypeParameterInstantiation | null | undefined
+> {
+ return path.get(
+ 'typeArguments' in path.node ? 'typeArguments' : 'typeParameters',
+ ) as NodePath<
+ TSTypeParameterInstantiation | TypeParameterInstantiation | null | undefined
+ >;
+}
diff --git a/packages/react-docgen/src/utils/getTypeFromReactComponent.ts b/packages/react-docgen/src/utils/getTypeFromReactComponent.ts
index 642fc3c7faf..9311a88b865 100644
--- a/packages/react-docgen/src/utils/getTypeFromReactComponent.ts
+++ b/packages/react-docgen/src/utils/getTypeFromReactComponent.ts
@@ -1,3 +1,4 @@
+import getTypeArguments from './getTypeArguments.js';
import type { NodePath } from '@babel/traverse';
import type Documentation from '../Documentation.js';
import getMemberValuePath from './getMemberValuePath.js';
@@ -36,11 +37,9 @@ function getStatelessPropsPath(
function getForwardRefGenericsType(
componentDefinition: NodePath,
): NodePath | null {
- const typeParameters = componentDefinition.get('typeParameters') as NodePath<
- TSTypeParameterInstantiation | null | undefined
- >;
+ const typeParameters = getTypeArguments(componentDefinition);
- if (typeParameters && typeParameters.hasNode()) {
+ if (typeParameters.isTSTypeParameterInstantiation()) {
const params = typeParameters.get('params');
return params[1] ?? null;
@@ -71,9 +70,9 @@ function findAssignedVariableType(
isReactBuiltinReference(typeName, 'VoidFunctionComponent') ||
isReactBuiltinReference(typeName, 'VFC')
) {
- const typeParameters = typeAnnotation.get('typeParameters');
+ const typeParameters = getTypeArguments(typeAnnotation);
- if (typeParameters.hasNode()) {
+ if (typeParameters.isTSTypeParameterInstantiation()) {
return typeParameters.get('params')[0] ?? null;
}
}
@@ -92,7 +91,16 @@ export default (componentDefinition: NodePath): NodePath[] => {
const typePaths: NodePath[] = [];
if (isReactComponentClass(componentDefinition)) {
- const superTypes = componentDefinition.get('superTypeParameters');
+ const superTypes = componentDefinition.get(
+ 'superTypeArguments' in componentDefinition.node
+ ? 'superTypeArguments'
+ : 'superTypeParameters',
+ ) as NodePath<
+ | TSTypeParameterInstantiation
+ | TypeParameterInstantiation
+ | null
+ | undefined
+ >;
if (superTypes.hasNode()) {
const params = superTypes.get('params');
@@ -219,17 +227,18 @@ function applyExtends(
const resolvedPath = resolveGenericTypeAnnotation(extendsPath);
if (resolvedPath) {
- if (
- resolvedPath.has('typeParameters') &&
- extendsPath.node.typeParameters
- ) {
+ const typeArguments = getTypeArguments(extendsPath);
+ const typeParameters = resolvedPath.get('typeParameters') as NodePath<
+ | TSTypeParameterDeclaration
+ | TypeParameterDeclaration
+ | null
+ | undefined
+ >;
+
+ if (typeParameters.hasNode() && typeArguments.hasNode()) {
typeParams = getTypeParameters(
- resolvedPath.get('typeParameters') as NodePath<
- TSTypeParameterDeclaration | TypeParameterDeclaration
- >,
- extendsPath.get('typeParameters') as NodePath<
- TSTypeParameterInstantiation | TypeParameterInstantiation
- >,
+ typeParameters,
+ typeArguments,
typeParams,
);
}
diff --git a/packages/react-docgen/src/utils/getTypeIdentifier.ts b/packages/react-docgen/src/utils/getTypeIdentifier.ts
index 99e3f1c154f..039463379ad 100644
--- a/packages/react-docgen/src/utils/getTypeIdentifier.ts
+++ b/packages/react-docgen/src/utils/getTypeIdentifier.ts
@@ -1,12 +1,18 @@
import type { NodePath } from '@babel/traverse';
export default function getTypeIdentifier(path: NodePath): NodePath | null {
- if (path.has('id')) {
+ if ('id' in path.node && path.node.id) {
return path.get('id') as NodePath;
} else if (path.isTSTypeReference()) {
return path.get('typeName');
- } else if (path.isTSExpressionWithTypeArguments()) {
- return path.get('expression');
+ } else if (
+ [
+ 'TSExpressionWithTypeArguments',
+ 'TSInterfaceHeritage',
+ 'TSClassImplements',
+ ].includes(path.node.type)
+ ) {
+ return path.get('expression') as NodePath;
}
return null;
diff --git a/packages/react-docgen/src/utils/getTypeParameters.ts b/packages/react-docgen/src/utils/getTypeParameters.ts
index da676462c29..cddf5cbd9d9 100644
--- a/packages/react-docgen/src/utils/getTypeParameters.ts
+++ b/packages/react-docgen/src/utils/getTypeParameters.ts
@@ -29,7 +29,8 @@ export default function getTypeParameters(
declaration
.get('params')
.forEach((paramPath: NodePath) => {
- const key = paramPath.node.name;
+ const name = paramPath.node.name as Identifier | string;
+ const key = typeof name === 'string' ? name : name.name;
const defaultProp = paramPath.get('default');
const defaultTypePath = defaultProp.hasNode() ? defaultProp : null;
const typePath =
diff --git a/packages/react-docgen/src/utils/normalizeClassDefinition.ts b/packages/react-docgen/src/utils/normalizeClassDefinition.ts
index 5704fcc47d3..532d0c01894 100644
--- a/packages/react-docgen/src/utils/normalizeClassDefinition.ts
+++ b/packages/react-docgen/src/utils/normalizeClassDefinition.ts
@@ -30,7 +30,7 @@ const explodedVisitors = visitors.explode({
if (
member &&
- !member.path.has('computed') &&
+ !('computed' in member.path.node && member.path.node.computed) &&
!member.path.isPrivateName()
) {
const property = classProperty(
diff --git a/packages/react-docgen/src/utils/resolveExportDeclaration.ts b/packages/react-docgen/src/utils/resolveExportDeclaration.ts
index 5081ab23ef9..3d3e2cbea64 100644
--- a/packages/react-docgen/src/utils/resolveExportDeclaration.ts
+++ b/packages/react-docgen/src/utils/resolveExportDeclaration.ts
@@ -13,7 +13,7 @@ export default function resolveExportDeclaration(
if (path.isExportDefaultDeclaration()) {
definitions.push(path.get('declaration'));
} else if (path.isExportNamedDeclaration()) {
- if (path.has('declaration')) {
+ if (path.node.declaration) {
const declaration = path.get('declaration');
if (declaration.isVariableDeclaration()) {
@@ -23,7 +23,7 @@ export default function resolveExportDeclaration(
} else if (declaration.isDeclaration()) {
definitions.push(declaration);
}
- } else if (path.has('specifiers')) {
+ } else if (path.node.specifiers.length > 0) {
path.get('specifiers').forEach((specifier) => {
if (specifier.isExportSpecifier()) {
definitions.push(specifier.get('local'));
diff --git a/packages/react-docgen/src/utils/unwrapBuiltinTSPropTypes.ts b/packages/react-docgen/src/utils/unwrapBuiltinTSPropTypes.ts
index 06f3cee24d4..645b5737309 100644
--- a/packages/react-docgen/src/utils/unwrapBuiltinTSPropTypes.ts
+++ b/packages/react-docgen/src/utils/unwrapBuiltinTSPropTypes.ts
@@ -1,3 +1,4 @@
+import getTypeArguments from './getTypeArguments.js';
import type { NodePath } from '@babel/traverse';
import isReactBuiltinReference from './isReactBuiltinReference.js';
@@ -15,7 +16,7 @@ export default function unwrapBuiltinTSPropTypes(typePath: NodePath): NodePath {
isReactBuiltinReference(typeName, 'PropsWithRef') ||
isReactBuiltinReference(typeName, 'PropsWithChildren')
) {
- const typeParameters = typePath.get('typeParameters');
+ const typeParameters = getTypeArguments(typePath);
if (typeParameters.hasNode()) {
const innerType = typeParameters.get('params')[0];