Skip to content

Commit 7c99f15

Browse files
authored
Fix typescript types without strict null checks (#789)
1 parent 0a3fdb0 commit 7c99f15

File tree

6 files changed

+52
-33
lines changed

6 files changed

+52
-33
lines changed

Diff for: .changeset/fuzzy-rice-dance.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'react-docgen': patch
3+
---
4+
5+
Fix TypeScript types when strict null checks are disabled

Diff for: packages/react-docgen/src/FileState.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import babelParse from './babelParser.js';
66
import type { TransformOptions } from '@babel/core';
77

88
// Workaround while babel is not a proper ES module
9-
const traverse = babelTraverse.default ?? babelTraverse;
9+
const traverse = babelTraverse.default ?? (babelTraverse as never);
1010

1111
export default class FileState {
1212
opts: TransformOptions;

Diff for: packages/react-docgen/src/utils/findFunctionReturn.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import type { NodePath } from '@babel/traverse';
22
import { visitors } from '@babel/traverse';
33
import resolveToValue from './resolveToValue.js';
44
import { ignore } from './traverse.js';
5-
import type { Node } from '@babel/types';
65

7-
type Predicate<T extends Node = Node> = (path: NodePath) => path is NodePath<T>;
8-
interface TraverseState<T extends Node = Node> {
6+
type Predicate<T extends NodePath> = (path: NodePath) => path is T;
7+
8+
interface TraverseState<T extends NodePath = NodePath> {
99
readonly predicate: Predicate<T>;
10-
resolvedReturnPath?: NodePath<T>;
10+
resolvedReturnPath?: T;
1111
readonly seen: WeakSet<NodePath>;
1212
}
1313

@@ -35,11 +35,11 @@ const explodedVisitors = visitors.explode<TraverseState>({
3535
},
3636
});
3737

38-
function resolvesToFinalValue<T extends Node = Node>(
38+
function resolvesToFinalValue<T extends NodePath>(
3939
path: NodePath,
4040
predicate: Predicate<T>,
4141
seen: WeakSet<NodePath>,
42-
): NodePath<T> | undefined {
42+
): T | undefined {
4343
// avoid returns with recursive function calls
4444
if (seen.has(path)) {
4545
return;
@@ -100,11 +100,11 @@ function resolvesToFinalValue<T extends Node = Node>(
100100
* 2. Find all occurrences of return values
101101
* For this the predicate acts more like a collector and always needs to return false
102102
*/
103-
function findFunctionReturnWithCache<T extends Node = Node>(
103+
function findFunctionReturnWithCache<T extends NodePath>(
104104
path: NodePath,
105105
predicate: Predicate<T>,
106106
seen: WeakSet<NodePath>,
107-
): NodePath<T> | undefined {
107+
): T | undefined {
108108
let functionPath: NodePath = path;
109109

110110
if (functionPath.isObjectProperty()) {
@@ -147,9 +147,9 @@ function findFunctionReturnWithCache<T extends Node = Node>(
147147
* 2. Find all occurrences of return values
148148
* For this the predicate acts more like a collector and always needs to return false
149149
*/
150-
export default function findFunctionReturn<T extends Node = Node>(
150+
export default function findFunctionReturn<T extends NodePath = NodePath>(
151151
path: NodePath,
152152
predicate: Predicate<T>,
153-
): NodePath<T> | undefined {
153+
): T | undefined {
154154
return findFunctionReturnWithCache(path, predicate, new WeakSet());
155155
}

Diff for: packages/react-docgen/src/utils/getFlowType.ts

+24-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import type {
2222
Identifier,
2323
InterfaceDeclaration,
2424
IntersectionTypeAnnotation,
25+
Node,
2526
NullableTypeAnnotation,
2627
NumberLiteralTypeAnnotation,
2728
ObjectTypeAnnotation,
@@ -77,18 +78,32 @@ function getFlowTypeWithRequirements(
7778
function handleKeysHelper(
7879
path: NodePath<GenericTypeAnnotation>,
7980
): ElementsType | null {
80-
let value = path.get('typeParameters').get('params')[0];
81+
const typeParams = path.get('typeParameters');
82+
83+
if (!typeParams.hasNode()) {
84+
return null;
85+
}
86+
87+
let value: NodePath<Node | null | undefined> | undefined =
88+
typeParams.get('params')[0];
89+
90+
if (!value) {
91+
return null;
92+
}
8193

8294
if (value.isTypeofTypeAnnotation()) {
83-
value = value.get('argument').get('id');
95+
value = value.get('argument').get('id') as NodePath<
96+
Node | null | undefined
97+
>;
8498
} else if (!value.isObjectTypeAnnotation()) {
85-
value = value.get('id');
99+
value = value.get('id') as NodePath<Node | null | undefined>;
86100
}
87-
const resolvedPath = resolveToValue(value);
101+
102+
const resolvedPath = value.hasNode() ? resolveToValue(value) : value;
88103

89104
if (
90-
resolvedPath &&
91-
(resolvedPath.isObjectExpression() || resolvedPath.isObjectTypeAnnotation())
105+
resolvedPath.isObjectExpression() ||
106+
resolvedPath.isObjectTypeAnnotation()
92107
) {
93108
const keys = resolveObjectToNameArray(resolvedPath, true);
94109

@@ -299,7 +314,7 @@ function handleNullableTypeAnnotation(
299314
path: NodePath<NullableTypeAnnotation>,
300315
typeParams: TypeParameters | null,
301316
): TypeDescriptor | null {
302-
const typeAnnotation = getTypeAnnotation(path);
317+
const typeAnnotation = getTypeAnnotation<FlowType>(path);
303318

304319
if (!typeAnnotation) return null;
305320

@@ -325,7 +340,7 @@ function handleFunctionTypeAnnotation(
325340
};
326341

327342
path.get('params').forEach((param) => {
328-
const typeAnnotation = getTypeAnnotation(param);
343+
const typeAnnotation = getTypeAnnotation<FlowType>(param);
329344

330345
type.signature.arguments.push({
331346
name: param.node.name ? param.node.name.name : '',
@@ -338,7 +353,7 @@ function handleFunctionTypeAnnotation(
338353
const rest = path.get('rest');
339354

340355
if (rest.hasNode()) {
341-
const typeAnnotation = getTypeAnnotation(rest);
356+
const typeAnnotation = getTypeAnnotation<FlowType>(rest);
342357

343358
type.signature.arguments.push({
344359
name: rest.node.name ? rest.node.name.name : '',

Diff for: packages/react-docgen/src/utils/getMethodDocumentation.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ import type {
44
ClassMethod,
55
ClassPrivateMethod,
66
ClassProperty,
7-
FlowType,
87
Function as FunctionType,
98
ObjectMethod,
109
ObjectProperty,
11-
TSType,
1210
} from '@babel/types';
1311
import { getDocblock } from './docblock.js';
1412
import getFlowType from './getFlowType.js';
@@ -78,7 +76,7 @@ function getMethodParamsDoc(methodPath: MethodNodePath): MethodParameter[] {
7876
// Extract param types.
7977
functionExpression.get('params').forEach((paramPath) => {
8078
let type: TypeDescriptor | null = null;
81-
const typePath = getTypeAnnotation<FlowType | TSType>(paramPath);
79+
const typePath = getTypeAnnotation(paramPath);
8280

8381
if (typePath) {
8482
if (typePath.isFlowType()) {
@@ -112,13 +110,15 @@ function getMethodReturnDoc(methodPath: MethodNodePath): MethodReturn | null {
112110
const functionExpression = getMethodFunctionExpression(methodPath);
113111

114112
if (functionExpression && functionExpression.node.returnType) {
115-
const returnType = getTypeAnnotation(
116-
functionExpression.get('returnType') as NodePath,
117-
);
113+
const returnType = getTypeAnnotation(functionExpression.get('returnType'));
118114

119-
if (returnType && returnType.isFlowType()) {
115+
if (!returnType) {
116+
return null;
117+
}
118+
119+
if (returnType.isFlowType()) {
120120
return { type: getFlowType(returnType, null) };
121-
} else if (returnType) {
121+
} else if (returnType.isTSType()) {
122122
return { type: getTSType(returnType, null) };
123123
}
124124
}

Diff for: packages/react-docgen/src/utils/getTypeAnnotation.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import type { NodePath } from '@babel/traverse';
2-
import type { FlowType } from '@babel/types';
2+
import type { FlowType, Node, TSType } from '@babel/types';
33

44
/**
55
* Gets the most inner valuable TypeAnnotation from path. If no TypeAnnotation
66
* can be found null is returned
77
*/
8-
export default function getTypeAnnotation<T = FlowType>(
9-
path: NodePath,
8+
export default function getTypeAnnotation<T extends Node = FlowType | TSType>(
9+
path: NodePath<Node | null | undefined>,
1010
): NodePath<T> | null {
1111
if (!path.has('typeAnnotation')) return null;
1212

@@ -20,6 +20,5 @@ export default function getTypeAnnotation<T = FlowType>(
2020
!resultPath.isTSType()
2121
);
2222

23-
// @ts-ignore
24-
return resultPath;
23+
return resultPath as NodePath<T>;
2524
}

0 commit comments

Comments
 (0)