= (x: Props) => {
+ const RenderMe = x.renderMe;
+ return (
+
+ {" "}
+ {x.person.name} {x.children}{" "}
+
+
+ );
+};
+
+class AsClassComponent extends React.PureComponent {
+ public render() {
+ const RenderMe = this.props.renderMe;
+ return (
+
+ {" "}
+ {this.props.person.name} {this.props.children}{" "}
+
+
+ );
+ }
+}
-export const makeRenamed = make;
+export const makeRenamed = AsClassComponent;
export default make;
diff --git a/src/Config_.re b/src/Config_.re
index 71ff1852c..43bb823db 100644
--- a/src/Config_.re
+++ b/src/Config_.re
@@ -22,6 +22,7 @@ type config = {
mutable emitFlowAny: bool,
mutable emitImportCurry: bool,
mutable emitImportPropTypes: bool,
+ mutable emitImportReact: bool,
exportInterfaces: bool,
generatedFileExtension: option(string),
importPath,
@@ -40,6 +41,7 @@ let default = {
emitFlowAny: false,
emitImportCurry: false,
emitImportPropTypes: false,
+ emitImportReact: false,
exportInterfaces: false,
generatedFileExtension: None,
importPath: Relative,
@@ -257,6 +259,7 @@ let readConfig = (~getConfigFile, ~getBsConfigFile, ~namespace) => {
emitFlowAny: false,
emitImportCurry: false,
emitImportPropTypes: false,
+ emitImportReact: false,
exportInterfaces,
generatedFileExtension,
importPath,
diff --git a/src/Converter.re b/src/Converter.re
index b40dbefa8..1776df8ba 100644
--- a/src/Converter.re
+++ b/src/Converter.re
@@ -18,7 +18,8 @@ and groupedArgConverter =
and fieldsC = list((string, t))
and functionC = {
argConverters: list(groupedArgConverter),
- functionName: option(string),
+ componentName: option(string),
+ isHook: bool,
retConverter: t,
typeVars: list(string),
uncurried: bool,
@@ -130,15 +131,23 @@ let typeGetConverterNormalized =
let (tConverter, tNormalized) = t |> visit(~visited);
(ArrayC(tConverter), Array(tNormalized, mutable_));
- | Function({argTypes, retType, typeVars, uncurried} as function_) =>
+ | Function(
+ {argTypes, componentName, retType, typeVars, uncurried} as function_,
+ ) =>
let argConverted =
argTypes |> List.map(typeToGroupedArgConverter(~visited));
let argConverters = argConverted |> List.map(fst);
let (retConverter, retNormalized) = retType |> visit(~visited);
+ let isHook =
+ switch (argTypes) {
+ | [Object(_)] => retType |> EmitType.isTypeReactElement(~config)
+ | _ => false
+ };
(
FunctionC({
argConverters,
- functionName: None,
+ componentName,
+ isHook,
retConverter,
typeVars,
uncurried,
@@ -451,7 +460,8 @@ let rec apply =
| FunctionC({
argConverters,
- functionName,
+ componentName,
+ isHook,
retConverter,
typeVars,
uncurried,
@@ -555,8 +565,14 @@ let rec apply =
let mkBody = bodyArgs => {
let useCurry = !uncurried && toJS && List.length(bodyArgs) > 1;
config.emitImportCurry = config.emitImportCurry || useCurry;
+ let hookToReason = !toJS && isHook;
+ let args = hookToReason ? [value, ...bodyArgs] : bodyArgs;
+ let functionName = hookToReason ? "React.createElement" : value;
+ if (hookToReason) {
+ config.emitImportReact = true;
+ };
Indent.break(~indent=indent1)
- ++ (value |> EmitText.funCall(~args=bodyArgs, ~useCurry) |> mkReturn);
+ ++ (functionName |> EmitText.funCall(~args, ~useCurry) |> mkReturn);
};
let convertedArgs = argConverters |> List.mapi(convertArg);
@@ -565,7 +581,7 @@ let rec apply =
let bodyArgs = convertedArgs |> List.map(snd) |> List.concat;
EmitText.funDef(
~bodyArgs,
- ~functionName,
+ ~functionName=componentName,
~funParams,
~indent,
~mkBody,
diff --git a/src/EmitJs.re b/src/EmitJs.re
index 191470269..f7807f7de 100644
--- a/src/EmitJs.re
+++ b/src/EmitJs.re
@@ -280,7 +280,7 @@ let rec emitCodeItem =
let componentNameTypeChecked = lastNameInPath ++ "TypeChecked";
/* Check the type of the component */
- let emitters = EmitType.emitRequireReact(~early=true, ~emitters, ~config);
+ config.emitImportReact = true;
let emitters =
emitExportType(
~early=true,
@@ -438,22 +438,16 @@ let rec emitCodeItem =
|> requireModule(~import=true, ~env, ~importPath, ~strict=true);
(emitters, importedAsName, env);
};
- let converter = type_ |> typeGetConverter;
- let isHook =
+ let type_ =
switch (type_) {
- | Function({argTypes: [Object(_)], retType})
+ | Function({argTypes: [Object(_)], retType} as function_)
when retType |> EmitType.isTypeReactElement(~config) =>
- true
- | _ => false
+ Function({...function_, componentName: Some(importFile)})
+ | _ => type_
};
- let converter =
- switch (converter) {
- | FunctionC(functionC) when isHook =>
- Converter.FunctionC({...functionC, functionName: Some(importFile)})
- | _ => converter
- };
+ let converter = type_ |> typeGetConverter;
let valueNameTypeChecked = valueName ++ "TypeChecked";
@@ -678,26 +672,16 @@ let rec emitCodeItem =
let fileNameBs = fileName |> ModuleName.forBsFile;
let envWithRequires =
fileNameBs |> requireModule(~import=false, ~env, ~importPath);
- let converter = type_ |> typeGetConverter;
let default = "default";
let make = "make";
- let hookType =
+ let (type_, hookType) =
switch (type_) {
- | Function({argTypes: [Object(_) as propsT], retType, typeVars})
+ | Function(
+ {argTypes: [Object(_) as propsT], retType, typeVars} as function_,
+ )
when retType |> EmitType.isTypeReactElement(~config) =>
- Some((propsT, retType, typeVars))
- | _ => None
- };
- /* Work around Flow issue with function components.
- If type annotated direcly, they are not checked. But typeof() works. */
- let flowFunctionTypeWorkaround =
- hookType != None && config.language == Flow;
-
- let converter =
- switch (converter) {
- | FunctionC(functionC) when hookType != None =>
let chopSuffix = suffix =>
resolvedName == suffix ?
"" :
@@ -714,9 +698,19 @@ let rec emitCodeItem =
let hookName =
(fileName |> ModuleName.toString)
++ (suffix == "" ? suffix : "_" ++ suffix);
- Converter.FunctionC({...functionC, functionName: Some(hookName)});
- | _ => converter
+
+ (
+ Function({...function_, componentName: Some(hookName)}),
+ Some((propsT, retType, typeVars)),
+ );
+ | _ => (type_, None)
};
+ /* Work around Flow issue with function components.
+ If type annotated direcly, they are not checked. But typeof() works. */
+ let flowFunctionTypeWorkaround =
+ hookType != None && config.language == Flow;
+
+ let converter = type_ |> typeGetConverter;
let name = originalName == default ? Runtime.default : resolvedName;
let hookNameForTypeof = name ++ "$$forTypeof";
@@ -1246,6 +1240,10 @@ let emitTranslationAsString =
~typeNameIsInterface=typeNameIsInterface(~env),
~variantTables,
);
+ let emitters =
+ config.emitImportReact ?
+ EmitType.emitImportReact(~emitters, ~config) : emitters;
+
let env =
config.emitImportCurry ?
ModuleName.curry
diff --git a/src/EmitType.re b/src/EmitType.re
index afc461b7a..0a9e57db2 100644
--- a/src/EmitType.re
+++ b/src/EmitType.re
@@ -46,9 +46,9 @@ let shimExtension = (~config) =>
let interfaceName = (~config, name) =>
config.exportInterfaces ? "I" ++ name : name;
-let typeReactComponent = (~config, ~propsTypeName) =>
- (config.language == Flow ? "React$ComponentType" : "React.ComponentClass")
- |> ident(~builtin=true, ~typeArgs=[ident(propsTypeName)]);
+let typeReactComponent = (~config, ~propsType) =>
+ (config.language == Flow ? "React$ComponentType" : "React.ComponentType")
+ |> ident(~builtin=true, ~typeArgs=[propsType]);
let typeReactContext = (~config, ~type_) =>
(config.language == Flow ? "React$Context" : "React.Context")
@@ -58,9 +58,6 @@ let typeReactElementFlow = ident(~builtin=true, "React$Node");
let typeReactElementTypeScript = ident(~builtin=true, "JSX.Element");
-let typeReactFunctionComponentTypeScript = (~propsType) =>
- ident(~builtin=true, ~typeArgs=[propsType], "React.FC");
-
let typeReactElement = (~config) =>
config.language == Flow ? typeReactElementFlow : typeReactElementTypeScript;
@@ -117,10 +114,7 @@ let rec renderType =
};
| Function({argTypes: [Object(closedFlag, fields)], retType, typeVars})
- when
- config.language == TypeScript
- && retType
- |> isTypeReactElement(~config) =>
+ when retType |> isTypeReactElement(~config) =>
let fields =
fields
|> List.map(field =>
@@ -137,11 +131,9 @@ let rec renderType =
),
}
);
- let functionComponentType =
- typeReactFunctionComponentTypeScript(
- ~propsType=Object(closedFlag, fields),
- );
- functionComponentType
+ let componentType =
+ typeReactComponent(~config, ~propsType=Object(closedFlag, fields));
+ componentType
|> renderType(~config, ~indent, ~typeNameIsInterface, ~inFunType);
| Function({argTypes, retType, typeVars}) =>
@@ -624,12 +616,12 @@ let emitRequire =
let require = (~early) => early ? Emitters.requireEarly : Emitters.require;
-let emitRequireReact = (~early, ~emitters, ~config) =>
+let emitImportReact = (~emitters, ~config) =>
switch (config.language) {
| Flow =>
emitRequire(
~importedValueOrComponent=false,
- ~early,
+ ~early=true,
~emitters,
~config,
~moduleName=ModuleName.react,
@@ -637,7 +629,7 @@ let emitRequireReact = (~early, ~emitters, ~config) =>
ImportPath.react,
)
| TypeScript =>
- "import * as React from 'react';" |> require(~early, ~emitters)
+ "import * as React from 'react';" |> require(~early=true, ~emitters)
| Untyped => emitters
};
diff --git a/src/EmitType.rei b/src/EmitType.rei
index 8002246b9..8fa7a8096 100644
--- a/src/EmitType.rei
+++ b/src/EmitType.rei
@@ -69,6 +69,8 @@ let emitHookTypeAsFunction:
) =>
Emitters.t;
+let emitImportReact: (~emitters: Emitters.t, ~config: config) => Emitters.t;
+
let emitImportTypeAs:
(
~emitters: Emitters.t,
@@ -112,9 +114,6 @@ let emitRequire:
) =>
Emitters.t;
-let emitRequireReact:
- (~early: bool, ~emitters: Emitters.t, ~config: config) => Emitters.t;
-
let emitTypeCast:
(
~config: config,
@@ -146,9 +145,7 @@ let outputFileSuffix: (~config: config) => string;
let shimExtension: (~config: config) => string;
-let typeReactComponent: (~config: config, ~propsTypeName: string) => type_;
-
-let typeReactFunctionComponentTypeScript: (~propsType: type_) => type_;
+let typeReactComponent: (~config: config, ~propsType: type_) => type_;
let typeReactContext: (~config: config, ~type_: type_) => type_;
diff --git a/src/GenTypeCommon.re b/src/GenTypeCommon.re
index 55519b4e5..2c35c982c 100644
--- a/src/GenTypeCommon.re
+++ b/src/GenTypeCommon.re
@@ -71,6 +71,7 @@ and field = {
}
and function_ = {
argTypes: list(type_),
+ componentName: option(string),
retType: type_,
typeVars: list(string),
uncurried: bool,
diff --git a/src/TranslateCoreType.re b/src/TranslateCoreType.re
index 4dcc2d07d..2f139d09e 100644
--- a/src/TranslateCoreType.re
+++ b/src/TranslateCoreType.re
@@ -149,7 +149,13 @@ let rec translateArrowType =
let argTypes = labeledConvertableTypes |> NamedArgs.group;
let functionType =
- Function({argTypes, retType, typeVars: [], uncurried: false});
+ Function({
+ argTypes,
+ componentName: None,
+ retType,
+ typeVars: [],
+ uncurried: false,
+ });
{dependencies: allDeps, type_: functionType};
}
diff --git a/src/TranslateTypeExprFromTypes.re b/src/TranslateTypeExprFromTypes.re
index 25010c793..cb6582b67 100644
--- a/src/TranslateTypeExprFromTypes.re
+++ b/src/TranslateTypeExprFromTypes.re
@@ -195,6 +195,7 @@ let translateConstr =
type_:
Function({
argTypes: [fromTranslation.type_],
+ componentName: None,
retType: toTranslation.type_,
typeVars: [],
uncurried: false,
@@ -210,6 +211,7 @@ let translateConstr =
type_:
Function({
argTypes: [propsTranslation.type_],
+ componentName: None,
retType: retTranslation.type_,
typeVars: [],
uncurried: false,
@@ -221,6 +223,7 @@ let translateConstr =
type_:
Function({
argTypes: [propsTranslation.type_],
+ componentName: None,
retType: EmitType.typeReactElement(~config),
typeVars: [],
uncurried: false,
@@ -308,6 +311,7 @@ let translateConstr =
type_:
Function({
argTypes: ts,
+ componentName: None,
retType: ret.type_,
typeVars: [],
uncurried: true,
@@ -328,6 +332,7 @@ let translateConstr =
type_:
Function({
argTypes: [],
+ componentName: None,
retType: ret.type_,
typeVars: [],
uncurried: true,
@@ -348,6 +353,7 @@ let translateConstr =
type_:
Function({
argTypes,
+ componentName: None,
retType: ret.type_,
typeVars: [],
uncurried: true,
@@ -523,7 +529,13 @@ let rec translateArrowType =
let argTypes = labeledConvertableTypes |> NamedArgs.group;
let functionType =
- Function({argTypes, retType, typeVars: [], uncurried: false});
+ Function({
+ argTypes,
+ componentName: None,
+ retType,
+ typeVars: [],
+ uncurried: false,
+ });
{dependencies: allDeps, type_: functionType};
}
diff --git a/src/Translation.re b/src/Translation.re
index d75c1f23c..e97948607 100644
--- a/src/Translation.re
+++ b/src/Translation.re
@@ -35,8 +35,7 @@ let combine = (translations: list(t)): t =>
/* Applies type parameters to types (for all) */
let abstractTheTypeParameters = (~typeVars, type_) =>
switch (type_) {
- | Function({argTypes, retType, uncurried, _}) =>
- Function({argTypes, retType, typeVars, uncurried})
+ | Function(function_) => Function({...function_, typeVars})
| _ => type_
};
@@ -199,13 +198,13 @@ let translateComponent =
"ReasonReact_component" |
"React_component",
typeArgs: [_state, ..._],
- } as ident,
+ } as id,
),
_,
} as function_,
) =>
let type_ =
- Function({...function_, retType: Ident({...ident, typeArgs: []})});
+ Function({...function_, retType: Ident({...id, typeArgs: []})});
/* Add children?:any to props type */
let propsType =
@@ -240,7 +239,8 @@ let translateComponent =
};
let resolvedTypeName = "Props" |> TypeEnv.addModulePath(~typeEnv);
let propsTypeName = resolvedTypeName |> ResolvedName.toString;
- let componentType = EmitType.typeReactComponent(~config, ~propsTypeName);
+ let componentType =
+ EmitType.typeReactComponent(~config, ~propsType=ident(propsTypeName));
let nestedModuleName = typeEnv |> TypeEnv.getNestedModuleName;