@@ -1557,7 +1557,7 @@ module V4 = struct
15571557 let makePropsTypeParamsTvar namedTypeList =
15581558 namedTypeList
15591559 |> List. filter_map (fun (_isOptional , label , _ , _interiorType ) ->
1560- if label = " key" || label = " ref " then None
1560+ if label = " key" then None
15611561 else Some (Typ. var @@ safeTypeFromValue (Labelled label)))
15621562
15631563 let stripOption coreType =
@@ -1566,13 +1566,37 @@ module V4 = struct
15661566 List. nth_opt coreTypes 0
15671567 | _ -> Some coreType
15681568
1569- (* make type params for make sig arguments and for external *)
1570- (* let make: React.componentLike<props<string, option<string>>, React.element> *)
1571- (* external make: React.componentLike<props< .. >, React.element> = "default" *)
1572- let makePropsTypeParams ?(stripExplicitOption = false ) namedTypeList =
1569+ let stripJsNullable coreType =
1570+ match coreType with
1571+ | {
1572+ ptyp_desc =
1573+ Ptyp_constr
1574+ ({txt = Ldot (Ldot (Lident " Js" , " Nullable" ), " t" )}, coreTypes);
1575+ } ->
1576+ List. nth_opt coreTypes 0
1577+ | _ -> Some coreType
1578+
1579+ (* Make type params of the props type *)
1580+ (* (Sig) let make: React.componentLike<props<string>, React.element> *)
1581+ (* (Str) let make = ({x, _}: props<'x>) => body *)
1582+ (* (Str) external make: React.componentLike<props< .. >, React.element> = "default" *)
1583+ let makePropsTypeParams ?(stripExplicitOption = false )
1584+ ?(stripExplicitJsNullableOfRef = false ) namedTypeList =
15731585 namedTypeList
15741586 |> List. filter_map (fun (isOptional , label , _ , interiorType ) ->
1575- if label = " key" || label = " ref" then None
1587+ if label = " key" then None
1588+ (* TODO: Worth thinking how about "ref_" or "_ref" usages *)
1589+ else if label = " ref" then
1590+ (*
1591+ If ref has a type annotation then use it, else `ReactDOM.Ref.currentDomRef.
1592+ For example, if JSX ppx is used for React Native, type would be different.
1593+ *)
1594+ match interiorType with
1595+ | {ptyp_desc = Ptyp_var label } -> Some (refType Location. none)
1596+ | _ ->
1597+ (* Strip explicit Js.Nullable.t in case of forwardRef *)
1598+ if stripExplicitJsNullableOfRef then stripJsNullable interiorType
1599+ else Some interiorType
15761600 (* Strip the explicit option type in implementation *)
15771601 (* let make = (~x: option<string>=?) => ... *)
15781602 else if isOptional && stripExplicitOption then
@@ -1584,10 +1608,6 @@ module V4 = struct
15841608 |> List. map (fun (isOptional , label , _ , interiorType ) ->
15851609 if label = " key" then
15861610 Type. field ~loc ~attrs: optionalAttr {txt = label; loc} interiorType
1587- else if label = " ref" then
1588- Type. field ~loc
1589- ~attrs: (if isOptional then optionalAttr else [] )
1590- {txt = label; loc} interiorType
15911611 else if isOptional then
15921612 Type. field ~loc ~attrs: optionalAttr {txt = label; loc}
15931613 (Typ. var @@ safeTypeFromValue @@ Labelled label)
@@ -1951,12 +1971,22 @@ module V4 = struct
19511971 | Pexp_fun
19521972 ( Nolabel ,
19531973 _,
1954- {
1955- ppat_desc =
1956- Ppat_var _ | Ppat_constraint ({ppat_desc = Ppat_var _ }, _);
1957- } ,
1974+ ( {
1975+ ppat_desc =
1976+ Ppat_var {txt} | Ppat_constraint ({ppat_desc = Ppat_var {txt} }, _);
1977+ } as pattern) ,
19581978 _expression ) ->
1959- (args, newtypes, coreType)
1979+ if txt = " ref" then
1980+ let type_ =
1981+ match pattern with
1982+ | {ppat_desc = Ppat_constraint (_ , type_ )} -> Some type_
1983+ | _ -> None
1984+ in
1985+ (* The ref arguement of forwardRef should be optional *)
1986+ ( (Optional " ref" , None , pattern, txt, pattern.ppat_loc, type_) :: args,
1987+ newtypes,
1988+ coreType )
1989+ else (args, newtypes, coreType)
19601990 | Pexp_fun (Nolabel, _ , pattern , _expression ) ->
19611991 Location. raise_errorf ~loc: pattern.ppat_loc
19621992 " React: react.component refs only support plain arguments and type \
@@ -2293,11 +2323,7 @@ module V4 = struct
22932323 let vbMatchList = List. map vbMatch namedArgWithDefaultValueList in
22942324 (* type props = { ... } *)
22952325 let propsRecordType =
2296- makePropsRecordType " props" emptyLoc
2297- ((if hasForwardRef then
2298- [(true , " ref" , [] , refType Location. none)]
2299- else [] )
2300- @ namedTypeList)
2326+ makePropsRecordType " props" emptyLoc namedTypeList
23012327 in
23022328 let innerExpression =
23032329 Exp. apply
@@ -2366,12 +2392,12 @@ module V4 = struct
23662392 | Pexp_fun
23672393 (arg_label, _default, ({ppat_loc; ppat_desc} as pattern), expr)
23682394 -> (
2369- let pattern = stripConstraint pattern in
2395+ let patternWithoutConstraint = stripConstraint pattern in
23702396 if isLabelled arg_label || isOptional arg_label then
23712397 returnedExpression
23722398 (( {loc = ppat_loc; txt = Lident (getLabel arg_label)},
23732399 {
2374- pattern with
2400+ patternWithoutConstraint with
23752401 ppat_attributes =
23762402 (if isOptional arg_label then optionalAttr else [] )
23772403 @ pattern.ppat_attributes;
@@ -2382,7 +2408,8 @@ module V4 = struct
23822408 (* Special case of nolabel arg "ref" in forwardRef fn *)
23832409 (* let make = React.forwardRef(ref => body) *)
23842410 match ppat_desc with
2385- | Ppat_var {txt} ->
2411+ | Ppat_var {txt}
2412+ | Ppat_constraint ({ppat_desc = Ppat_var {txt} } , _ ) ->
23862413 returnedExpression patternsWithLabel
23872414 (( {loc = ppat_loc; txt = Lident txt},
23882415 {
@@ -2400,27 +2427,29 @@ module V4 = struct
24002427 let patternsWithLabel, patternsWithNolabel, expression =
24012428 returnedExpression [] [] expression
24022429 in
2403- let pattern =
2404- match patternsWithLabel with
2405- | [] -> Pat. any ()
2406- | _ -> Pat. record (List. rev patternsWithLabel) Open
2407- in
24082430 (* add pattern matching for optional prop value *)
24092431 let expression =
24102432 if List. length vbMatchList = 0 then expression
24112433 else Exp. let_ Nonrecursive vbMatchList expression
24122434 in
24132435 let expression =
2436+ (* (ref) => expr *)
24142437 List. fold_left
24152438 (fun expr (_ , pattern ) -> Exp. fun_ Nolabel None pattern expr)
24162439 expression patternsWithNolabel
24172440 in
2441+ let recordPattern =
2442+ match patternsWithLabel with
2443+ | [] -> Pat. any ()
2444+ | _ -> Pat. record (List. rev patternsWithLabel) Open
2445+ in
24182446 let expression =
24192447 Exp. fun_ Nolabel None
2420- (Pat. constraint_ pattern
2448+ (Pat. constraint_ recordPattern
24212449 (Typ. constr ~loc: emptyLoc
24222450 {txt = Lident " props" ; loc = emptyLoc}
24232451 (makePropsTypeParams ~strip ExplicitOption:true
2452+ ~strip ExplicitJsNullableOfRef:hasForwardRef
24242453 namedTypeList)))
24252454 expression
24262455 in
0 commit comments