@@ -143,7 +143,8 @@ let emit_code_item ~config ~emitters ~module_items_emitter ~env ~file_name
143143 Log_. item " Code Item: %s\n "
144144 (code_item |> code_item_to_string ~config ~type_name_is_interface );
145145 match code_item with
146- | ImportValue {as_path; import_annotation; type_; value_name} ->
146+ | ImportValue {as_path; import_annotation; type_; value_name; export_binding}
147+ ->
147148 let import_path = import_annotation.import_path in
148149 let first_name_in_path, rest_of_path =
149150 match value_name = as_path with
@@ -163,8 +164,15 @@ let emit_code_item ~config ~emitters ~module_items_emitter ~env ~file_name
163164 in
164165 (emitters, value_name_not_checked, env)
165166 in
166- let type_ =
167+ (* Extract potential satisfies wrapper to drive custom emission. *)
168+ let satisfies_rescript_type_opt =
167169 match type_ with
170+ | Ident {builtin = _; name; type_args = [rescript_t; _]}
171+ when SatisfiesHelpers. is_helper_ident name -> Some rescript_t
172+ | _ -> None
173+ in
174+ let adjust_for_function_component t =
175+ match t with
168176 | Function
169177 ({
170178 arg_types = [{a_type = Object (closed_flag, fields); a_name}];
@@ -217,44 +225,81 @@ let emit_code_item ~config ~emitters ~module_items_emitter ~env ~file_name
217225 }
218226 in
219227 Function function_
220- | _ -> type_)
221- | _ -> type_
228+ | _ -> t)
229+ | _ -> t
230+ in
231+ let type_for_emit = adjust_for_function_component type_ in
232+ let value_name_type_checked =
233+ let base = value_name ^ " TypeChecked" in
234+ match export_binding with
235+ | false -> " _" ^ base
236+ | true -> base
222237 in
223- let value_name_type_checked = value_name ^ " TypeChecked" in
224238 let emitters =
225- imported_as_name ^ rest_of_path
226- |> EmitType. emit_export_const ~config
227- ~comment:
228- (" In case of type error, check the type of '" ^ value_name
229- ^ " ' in '"
230- ^ (file_name |> ModuleName. to_string)
231- ^ " .res'" ^ " and '"
232- ^ (import_path |> ImportPath. emit)
233- ^ " '." )
234- ~early: true ~emitters ~name: value_name_type_checked ~type_
235- ~type_name_is_interface
239+ match satisfies_rescript_type_opt with
240+ | Some rescript_type ->
241+ let rescript_type = adjust_for_function_component rescript_type in
242+ let expr = imported_as_name ^ rest_of_path in
243+ (* Non-exported const for the checked binding, emitted early for ordering. *)
244+ let comment =
245+ match export_binding with
246+ | false -> " Check imported TypeScript value conforms to ReScript type"
247+ | true -> " "
248+ in
249+ EmitType. emit_const_satisfies ~early: true ~emitters ~config
250+ ~satisfies_type: rescript_type ~type_name_is_interface ~comment
251+ value_name_type_checked expr
252+ | None ->
253+ imported_as_name ^ rest_of_path
254+ |> EmitType. emit_export_const ~config
255+ ~comment:
256+ (" In case of type error, check the type of '" ^ value_name
257+ ^ " ' in '"
258+ ^ (file_name |> ModuleName. to_string)
259+ ^ " .res'" ^ " and '"
260+ ^ (import_path |> ImportPath. emit)
261+ ^ " '." )
262+ ~early: true ~emitters ~name: value_name_type_checked ~type_: type_for_emit
263+ ~type_name_is_interface
236264 in
237265 let value_name_not_default =
238266 match value_name = " default" with
239267 | true -> Runtime. default
240268 | false -> value_name
241269 in
242- let emitters =
243- value_name_type_checked
244- |> EmitType. emit_type_cast ~config ~type_ ~type_name_is_interface
245- |> EmitType. emit_export_const
246- ~comment:
247- (" Export '" ^ value_name_not_default
248- ^ " ' early to allow circular import from the '.bs.js' file." )
249- ~config ~early: true ~emitters ~name: value_name_not_default
250- ~type_: unknown ~type_name_is_interface
251- in
252- let emitters =
253- match value_name = " default" with
254- | true -> EmitType. emit_export_default ~emitters value_name_not_default
255- | false -> emitters
270+ let env, emitters =
271+ match export_binding with
272+ | false -> (env, emitters)
273+ | true ->
274+ let emitters =
275+ match satisfies_rescript_type_opt with
276+ | Some _ ->
277+ (* For satisfies, we can assign the typed binding directly without casts. *)
278+ EmitType. emit_export_const_assign_value ~early: true ~emitters ~config
279+ ~name: value_name_not_default ~type_: type_for_emit
280+ ~type_name_is_interface value_name_type_checked
281+ ~comment:
282+ (" Export '" ^ value_name_not_default
283+ ^ " ' early to allow circular import from the '.bs.js' file." )
284+ | None ->
285+ value_name_type_checked
286+ |> EmitType. emit_type_cast ~config ~type_: type_for_emit
287+ ~type_name_is_interface
288+ |> EmitType. emit_export_const
289+ ~comment:
290+ (" Export '" ^ value_name_not_default
291+ ^ " ' early to allow circular import from the '.bs.js' file." )
292+ ~config ~early: true ~emitters ~name: value_name_not_default
293+ ~type_: unknown ~type_name_is_interface
294+ in
295+ let emitters =
296+ match value_name = " default" with
297+ | true -> EmitType. emit_export_default ~emitters value_name_not_default
298+ | false -> emitters
299+ in
300+ ({env with imported_value_or_component = true }, emitters)
256301 in
257- ({ env with imported_value_or_component = true } , emitters)
302+ (env, emitters)
258303 | ExportValue
259304 {doc_string; module_access_path; original_name; resolved_name; type_} ->
260305 let resolved_name_str = ResolvedName. to_string resolved_name in
0 commit comments