diff --git a/src/utils/__tests__/__snapshots__/getFlowType-test.js.snap b/src/utils/__tests__/__snapshots__/getFlowType-test.js.snap new file mode 100644 index 00000000000..e1e91b901bb --- /dev/null +++ b/src/utils/__tests__/__snapshots__/getFlowType-test.js.snap @@ -0,0 +1,107 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getFlowType handles ObjectTypeSpreadProperty 1`] = ` +Object { + "name": "signature", + "raw": "{| apple: string, banana: string, ...OtherFruits |}", + "signature": Object { + "properties": Array [ + Object { + "key": "apple", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "banana", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "orange", + "value": Object { + "name": "string", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getFlowType handles nested ObjectTypeSpreadProperty 1`] = ` +Object { + "name": "signature", + "raw": "{| apple: string, banana: string, ...BreakfastFruits |}", + "signature": Object { + "properties": Array [ + Object { + "key": "apple", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "banana", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "mango", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "orange", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "lemon", + "value": Object { + "name": "string", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getFlowType handles unresolved ObjectTypeSpreadProperty 1`] = ` +Object { + "name": "signature", + "raw": "{| apple: string, banana: string, ...MyType |}", + "signature": Object { + "properties": Array [ + Object { + "key": "apple", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "banana", + "value": Object { + "name": "string", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; diff --git a/src/utils/__tests__/getFlowType-test.js b/src/utils/__tests__/getFlowType-test.js index 367c974ecb4..41207f3427d 100644 --- a/src/utils/__tests__/getFlowType-test.js +++ b/src/utils/__tests__/getFlowType-test.js @@ -745,4 +745,43 @@ describe('getFlowType', () => { raw: '{ subAction: SubAction }', }); }); + + it('handles ObjectTypeSpreadProperty', () => { + const typePath = statement(` + var x: {| apple: string, banana: string, ...OtherFruits |} = 2; + type OtherFruits = { orange: string } + `) + .get('declarations', 0) + .get('id') + .get('typeAnnotation') + .get('typeAnnotation'); + + expect(getFlowType(typePath)).toMatchSnapshot(); + }); + + it('handles unresolved ObjectTypeSpreadProperty', () => { + const typePath = statement(` + var x: {| apple: string, banana: string, ...MyType |} = 2; + `) + .get('declarations', 0) + .get('id') + .get('typeAnnotation') + .get('typeAnnotation'); + + expect(getFlowType(typePath)).toMatchSnapshot(); + }); + + it('handles nested ObjectTypeSpreadProperty', () => { + const typePath = statement(` + var x: {| apple: string, banana: string, ...BreakfastFruits |} = 2; + type BreakfastFruits = { mango: string, ...CitrusFruits }; + type CitrusFruits = { orange: string, lemon: string }; + `) + .get('declarations', 0) + .get('id') + .get('typeAnnotation') + .get('typeAnnotation'); + + expect(getFlowType(typePath)).toMatchSnapshot(); + }); }); diff --git a/src/utils/getFlowType.js b/src/utils/getFlowType.js index 5eb1ad7ff7c..621c5d46310 100644 --- a/src/utils/getFlowType.js +++ b/src/utils/getFlowType.js @@ -201,6 +201,18 @@ function handleObjectTypeAnnotation( key: ((getPropertyName(param): any): string), value: getFlowTypeWithRequirements(param.get('value'), typeParams), }); + } else if (t.ObjectTypeSpreadProperty.check(param.node)) { + let spreadObject = resolveToValue(param.get('argument')); + if (t.GenericTypeAnnotation.check(spreadObject.node)) { + const typeAlias = resolveToValue(spreadObject.get('id')); + if (t.ObjectTypeAnnotation.check(typeAlias.get('right').node)) { + spreadObject = resolveToValue(typeAlias.get('right')); + } + } + if (t.ObjectTypeAnnotation.check(spreadObject.node)) { + const props = handleObjectTypeAnnotation(spreadObject, typeParams); + type.signature.properties.push(...props.signature.properties); + } } });