Skip to content

Commit

Permalink
fix crash when handling mapped types (#745)
Browse files Browse the repository at this point in the history
  • Loading branch information
danez committed Jan 28, 2023
1 parent da91511 commit 8fe3dbf
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/famous-needles-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-docgen': patch
---

Fix crash when using TypeScript mapped types
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,75 @@ exports[`getTSType > handles long type cycles 1`] = `
}
`;
exports[`getTSType > handles mapped type 1`] = `
{
"name": "signature",
"raw": "{
[Property in keyof Type]: number;
}",
"signature": {
"properties": [
{
"key": {
"name": "X",
"required": true,
},
"value": {
"name": "number",
},
},
],
},
"type": "object",
}
`;
exports[`getTSType > handles mapped type with implicit any 1`] = `
{
"name": "signature",
"raw": "{
[Property in keyof Type];
}",
"signature": {
"properties": [
{
"key": {
"name": "X",
"required": true,
},
"value": {
"name": "any",
},
},
],
},
"type": "object",
}
`;
exports[`getTSType > handles mapped type without typeParam 1`] = `
{
"name": "signature",
"raw": "{
[Property in keyof X]: string;
}",
"signature": {
"properties": [
{
"key": {
"name": "X",
"required": true,
},
"value": {
"name": "string",
},
},
],
},
"type": "object",
}
`;
exports[`getTSType > handles mapped types 1`] = `
{
"name": "signature",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,4 @@ describe('getMemberExpressionValuePath', () => {
);
});
});

//TODO test arrow assigned to destructuring
});
42 changes: 42 additions & 0 deletions packages/react-docgen/src/utils/__tests__/getTSType-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,4 +651,46 @@ describe('getTSType', () => {

expect(getTSType(typePath)).toMatchSnapshot();
});

test('handles mapped type', () => {
const typePath = typeAlias(`
let action: OptionsFlags<X>;
type OptionsFlags<Type> = {
[Property in keyof Type]: number;
};
interface X {
foo: string
}
`);

expect(getTSType(typePath)).toMatchSnapshot();
});

test('handles mapped type with implicit any', () => {
const typePath = typeAlias(`
let action: OptionsFlags<X>;
type OptionsFlags<Type> = {
[Property in keyof Type];
};
interface X {
foo: string
}
`);

expect(getTSType(typePath)).toMatchSnapshot();
});

test('handles mapped type without typeParam', () => {
const typePath = typeAlias(`
let action: OptionsFlags;
type OptionsFlags = {
[Property in keyof X]: string;
};
interface X {
foo: string
}
`);

expect(getTSType(typePath)).toMatchSnapshot();
});
});
4 changes: 1 addition & 3 deletions packages/react-docgen/src/utils/getPropType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ function getEnumValuesFromArrayExpression(
const values: Array<Record<string, unknown>> = [];

path.get('elements').forEach(elementPath => {
// Array holes TODO test
if (elementPath.node == null) return;
if (!elementPath.hasNode()) return;

if (elementPath.isSpreadElement()) {
const value = resolveToValue(elementPath.get('argument'));
Expand Down Expand Up @@ -85,7 +84,6 @@ function getPropTypeOneOfType(argumentPath: NodePath): PropTypeDescriptor {
type.value = printValue(argumentPath);
} else {
type.value = argumentPath.get('elements').map(elementPath => {
// Array holes TODO test
if (!elementPath.hasNode()) return;
const descriptor: PropTypeDescriptor = getPropType(elementPath);
const docs = getDocblock(
Expand Down
22 changes: 10 additions & 12 deletions packages/react-docgen/src/utils/getTSType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ function handleTSIntersectionType(
};
}

// type OptionsFlags<Type> = { [Property in keyof Type]; };
function handleTSMappedType(
path: NodePath<TSMappedType>,
typeParams: TypeParameters | null,
Expand All @@ -269,12 +270,7 @@ function handleTSMappedType(
if (typeAnnotation.hasNode()) {
value = getTSTypeWithResolvedTypes(typeAnnotation, typeParams);
} else {
value = { name: 'any' }; //TODO test
/**
type OptionsFlags<Type> = {
[Property in keyof Type];
};
*/
value = { name: 'any' };
}

return {
Expand Down Expand Up @@ -385,6 +381,7 @@ function handleTSTypeQuery(

function handleTSTypeOperator(
path: NodePath<TSTypeOperator>,
typeParams: TypeParameters | null,
): TypeDescriptor<TSFunctionSignatureType> | null {
if (path.node.operator !== 'keyof') {
return null;
Expand All @@ -396,14 +393,13 @@ function handleTSTypeOperator(
value = value.get('exprName');
} else if ('id' in value.node) {
value = value.get('id') as NodePath;
} else if (value.isTSTypeReference()) {
return getTSTypeWithResolvedTypes(value, typeParams);
}

const resolvedPath = resolveToValue(value);

if (
resolvedPath &&
(resolvedPath.isObjectExpression() || resolvedPath.isTSTypeLiteral())
) {
if (resolvedPath.isObjectExpression() || resolvedPath.isTSTypeLiteral()) {
const keys = resolveObjectToNameArray(resolvedPath, true);

if (keys) {
Expand Down Expand Up @@ -468,7 +464,7 @@ function getTSTypeWithResolvedTypes(
}

const node = path.node;
let type: TypeDescriptor;
let type: TypeDescriptor | null = null;
let typeAliasName: string | null = null;

if (path.parentPath.isTSTypeAliasDeclaration()) {
Expand Down Expand Up @@ -503,7 +499,9 @@ function getTSTypeWithResolvedTypes(
};
} else if (node.type in namedTypes) {
type = namedTypes[node.type](path, typeParams);
} else {
}

if (!type) {
type = { name: 'unknown' };
}

Expand Down

0 comments on commit 8fe3dbf

Please sign in to comment.