Skip to content

Commit

Permalink
Merge pull request #318 from Muritavo/feature/type_from_generics
Browse files Browse the repository at this point in the history
Inferring type from constrained generics
  • Loading branch information
pvasek authored Jan 2, 2021
2 parents 820515a + a0e71e5 commit ab12fad
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 7 deletions.
37 changes: 37 additions & 0 deletions src/__tests__/data/GenericWithExtends.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//In our case we have a component that works like the foolowing

type SampleUnion = 'value 1' | 'value 2' | 'value 3' | 'value 4' | 'value n';
type SampleObject = {
propA: string;
propB: object;
propC: number;
};
class Base {
propA: string = 'A';
}
class SampleUnionNonGeneric extends Base {
propB: string = 'B';
}

export const GenericWithExtends = <
G extends SampleUnion,
A extends number[],
O extends { prop1: number }
>(props: {
/** sampleUnionProp description */
sampleUnionProp: G;
/** sampleUnionNonGeneric description */
sampleUnionNonGeneric: SampleUnionNonGeneric;
/** sampleObjectProp description */
sampleObjectProp: SampleObject;
/** sampleNumberProp description */
sampleNumberProp: number;
/** sampleGenericArray description */
sampleGenericArray: A;
/** sampleGenericObject description */
sampleGenericObject: O;
/** sampleInlineObject description */
sampleInlineObject: { propA: string };
}) => {
return <div>test</div>;
};
66 changes: 59 additions & 7 deletions src/__tests__/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ describe('parser', () => {
it('should parse react stateless component with generic intersection + union overlap props - simple', () => {
check('SimpleGenericUnionIntersection', {
SimpleGenericUnionIntersection: {
as: { type: 'T', description: '' },
as: { type: 'any', description: '' },
foo: {
description:
'The foo prop should not repeat the description\nThe foo prop should not repeat the description',
Expand All @@ -528,7 +528,7 @@ describe('parser', () => {
check('ComplexGenericUnionIntersection', {
ComplexGenericUnionIntersection: {
as: {
type: 'E',
type: 'ElementType<any>',
required: false,
description: 'Render the component as another component'
},
Expand Down Expand Up @@ -558,7 +558,7 @@ describe('parser', () => {
check('ComplexGenericUnionIntersectionWithOmit', {
ComplexGenericUnionIntersectionWithOmit: {
as: {
type: 'E',
type: 'ElementType<any>',
required: false,
description: 'Render the component as another component'
},
Expand Down Expand Up @@ -741,11 +741,11 @@ describe('parser', () => {
});
});

it("should parse functional component component defined as function as default export", () => {
check("FunctionDeclarationAsDefaultExport", {
it('should parse functional component component defined as function as default export', () => {
check('FunctionDeclarationAsDefaultExport', {
Jumbotron: {
prop1: { type: "string", required: true },
},
prop1: { type: 'string', required: true }
}
});
});

Expand Down Expand Up @@ -1104,6 +1104,58 @@ describe('parser', () => {
}
);
});

it('Should infer types from constraint type (generic with extends)', () => {
check(
'GenericWithExtends',
{
GenericWithExtends: {
sampleUnionProp: {
raw: 'SampleUnion',
type: 'enum',
value: [
{
value: '"value 1"'
},
{
value: '"value 2"'
},
{
value: '"value 3"'
},
{
value: '"value 4"'
},
{
value: '"value n"'
}
]
},
sampleUnionNonGeneric: {
type: 'SampleUnionNonGeneric'
},
sampleObjectProp: {
type: 'SampleObject'
},
sampleNumberProp: {
type: 'number'
},
sampleGenericArray: {
type: 'number[]'
},
sampleGenericObject: {
type: '{ prop1: number; }'
},
sampleInlineObject: {
type: '{ propA: string; }'
}
}
},
true,
null,
{ shouldExtractLiteralValuesFromEnum: true }
);
});
});

describe('Extracting values from unions', () => {
Expand Down
6 changes: 6 additions & 0 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,12 @@ export class Parser {
}

public getDocgenType(propType: ts.Type, isRequired: boolean): PropItemType {
// When we are going to process the type, we check if this type has a constraint (is a generic type with constraint)
if (propType.getConstraint()) {
// If so, we assing the property the type that is the constraint
propType = propType.getConstraint()!;
}

let propTypeString = this.checker.typeToString(propType);

if (propType.isUnion()) {
Expand Down

0 comments on commit ab12fad

Please sign in to comment.