@@ -233,7 +233,7 @@ let recordFromProps ~loc ~removeKey callArguments =
233233let makePropsTypeParamsTvar namedTypeList =
234234 namedTypeList
235235 |> List. filter_map (fun (_isOptional , label , _ , _interiorType ) ->
236- if label = " key" || label = " ref " then None
236+ if label = " key" then None
237237 else Some (Typ. var @@ safeTypeFromValue (Labelled label)))
238238
239239let stripOption coreType =
@@ -242,13 +242,36 @@ let stripOption coreType =
242242 List. nth_opt coreTypes 0 [@ doesNotRaise]
243243 | _ -> Some coreType
244244
245- (* make type params for make sig arguments and for external *)
246- (* let make: React.componentLike<props<string, option<string>>, React.element> *)
247- (* external make: React.componentLike<props< .. >, React.element> = "default" *)
248- let makePropsTypeParams ?(stripExplicitOption = false ) namedTypeList =
245+ let stripJsNullable coreType =
246+ match coreType with
247+ | {
248+ ptyp_desc =
249+ Ptyp_constr ({txt = Ldot (Ldot (Lident " Js" , " Nullable" ), " t" )}, coreTypes);
250+ } ->
251+ List. nth_opt coreTypes 0
252+ | _ -> Some coreType
253+
254+ (* Make type params of the props type *)
255+ (* (Sig) let make: React.componentLike<props<string>, React.element> *)
256+ (* (Str) let make = ({x, _}: props<'x>) => body *)
257+ (* (Str) external make: React.componentLike<props< .. >, React.element> = "default" *)
258+ let makePropsTypeParams ?(stripExplicitOption = false )
259+ ?(stripExplicitJsNullableOfRef = false ) namedTypeList =
249260 namedTypeList
250261 |> List. filter_map (fun (isOptional , label , _ , interiorType ) ->
251- if label = " key" || label = " ref" then None
262+ if label = " key" then None
263+ (* TODO: Worth thinking how about "ref_" or "_ref" usages *)
264+ else if label = " ref" then
265+ (*
266+ If ref has a type annotation then use it, else `ReactDOM.Ref.currentDomRef.
267+ For example, if JSX ppx is used for React Native, type would be different.
268+ *)
269+ match interiorType with
270+ | {ptyp_desc = Ptyp_var "ref" } -> Some (refType Location. none)
271+ | _ ->
272+ (* Strip explicit Js.Nullable.t in case of forwardRef *)
273+ if stripExplicitJsNullableOfRef then stripJsNullable interiorType
274+ else Some interiorType
252275 (* Strip the explicit option type in implementation *)
253276 (* let make = (~x: option<string>=?) => ... *)
254277 else if isOptional && stripExplicitOption then stripOption interiorType
@@ -259,10 +282,6 @@ let makeLabelDecls ~loc namedTypeList =
259282 |> List. map (fun (isOptional , label , _ , interiorType ) ->
260283 if label = " key" then
261284 Type. field ~loc ~attrs: optionalAttr {txt = label; loc} interiorType
262- else if label = " ref" then
263- Type. field ~loc
264- ~attrs: (if isOptional then optionalAttr else [] )
265- {txt = label; loc} interiorType
266285 else if isOptional then
267286 Type. field ~loc ~attrs: optionalAttr {txt = label; loc}
268287 (Typ. var @@ safeTypeFromValue @@ Labelled label)
@@ -614,9 +633,22 @@ let rec recursivelyTransformNamedArgsForMake mapper expr args newtypes coreType
614633 | Pexp_fun
615634 ( Nolabel ,
616635 _,
617- {ppat_desc = Ppat_var _ | Ppat_constraint ({ppat_desc = Ppat_var _}, _)},
636+ ({
637+ ppat_desc =
638+ Ppat_var {txt} | Ppat_constraint ({ppat_desc = Ppat_var {txt}}, _);
639+ } as pattern),
618640 _expression ) ->
619- (args, newtypes, coreType)
641+ if txt = " ref" then
642+ let type_ =
643+ match pattern with
644+ | {ppat_desc = Ppat_constraint (_ , type_ )} -> Some type_
645+ | _ -> None
646+ in
647+ (* The ref arguement of forwardRef should be optional *)
648+ ( (Optional " ref" , None , pattern, txt, pattern.ppat_loc, type_) :: args,
649+ newtypes,
650+ coreType )
651+ else (args, newtypes, coreType)
620652 | Pexp_fun (Nolabel, _ , pattern , _expression ) ->
621653 Location. raise_errorf ~loc: pattern.ppat_loc
622654 " React: react.component refs only support plain arguments and type \
@@ -943,10 +975,7 @@ let transformStructureItem ~config mapper item =
943975 let vbMatchList = List. map vbMatch namedArgWithDefaultValueList in
944976 (* type props = { ... } *)
945977 let propsRecordType =
946- makePropsRecordType " props" emptyLoc
947- ((if hasForwardRef then [(true , " ref" , [] , refType Location. none)]
948- else [] )
949- @ namedTypeList)
978+ makePropsRecordType " props" emptyLoc namedTypeList
950979 in
951980 let innerExpression =
952981 Exp. apply
@@ -1013,12 +1042,12 @@ let transformStructureItem ~config mapper item =
10131042 | Pexp_fun
10141043 (arg_label, _default, ({ppat_loc; ppat_desc} as pattern), expr)
10151044 -> (
1016- let pattern = stripConstraint pattern in
1045+ let patternWithoutConstraint = stripConstraint pattern in
10171046 if isLabelled arg_label || isOptional arg_label then
10181047 returnedExpression
10191048 (( {loc = ppat_loc; txt = Lident (getLabel arg_label)},
10201049 {
1021- pattern with
1050+ patternWithoutConstraint with
10221051 ppat_attributes =
10231052 (if isOptional arg_label then optionalAttr else [] )
10241053 @ pattern.ppat_attributes;
@@ -1029,7 +1058,8 @@ let transformStructureItem ~config mapper item =
10291058 (* Special case of nolabel arg "ref" in forwardRef fn *)
10301059 (* let make = React.forwardRef(ref => body) *)
10311060 match ppat_desc with
1032- | Ppat_var {txt} ->
1061+ | Ppat_var {txt}
1062+ | Ppat_constraint ({ppat_desc = Ppat_var {txt} } , _ ) ->
10331063 returnedExpression patternsWithLabel
10341064 (( {loc = ppat_loc; txt = Lident txt},
10351065 {
@@ -1046,27 +1076,29 @@ let transformStructureItem ~config mapper item =
10461076 let patternsWithLabel, patternsWithNolabel, expression =
10471077 returnedExpression [] [] expression
10481078 in
1049- let pattern =
1050- match patternsWithLabel with
1051- | [] -> Pat. any ()
1052- | _ -> Pat. record (List. rev patternsWithLabel) Open
1053- in
10541079 (* add pattern matching for optional prop value *)
10551080 let expression =
10561081 if List. length vbMatchList = 0 then expression
10571082 else Exp. let_ Nonrecursive vbMatchList expression
10581083 in
1084+ (* (ref) => expr *)
10591085 let expression =
10601086 List. fold_left
10611087 (fun expr (_ , pattern ) -> Exp. fun_ Nolabel None pattern expr)
10621088 expression patternsWithNolabel
10631089 in
1090+ let recordPattern =
1091+ match patternsWithLabel with
1092+ | [] -> Pat. any ()
1093+ | _ -> Pat. record (List. rev patternsWithLabel) Open
1094+ in
10641095 let expression =
10651096 Exp. fun_ Nolabel None
1066- (Pat. constraint_ pattern
1097+ (Pat. constraint_ recordPattern
10671098 (Typ. constr ~loc: emptyLoc
10681099 {txt = Lident " props" ; loc = emptyLoc}
1069- (makePropsTypeParams ~strip ExplicitOption:true namedTypeList)))
1100+ (makePropsTypeParams ~strip ExplicitOption:true
1101+ ~strip ExplicitJsNullableOfRef:hasForwardRef namedTypeList)))
10701102 expression
10711103 in
10721104 (* let make = ({id, name, ...}: props<'id, 'name, ...>) => { ... } *)
0 commit comments