A few small questions

Thank you, this clarified it for me.

@yawaramin

The cors API returns an Error if something fails, otherwise some success object:

type corsFn = (Next.Request.t, Next.Response.t, t => unit) => unit

@module("cors")
external create: {..} => corsFn = "default"

let allow = (corsFn: t, req: Next.Request.t, res: Next.Response.t) =>
  Promise.make((resolve, _) =>
    corsFn(req, res, result => {
      //if (result instanceof Error) {
      //reject(result)
      //return
      //}
      resolve(. result)
    })
  )

Which cors API is this? Can you point to some documentation or post a JavaScript example which shows the behaviour?

Thank you @yawaramin. I appreciate your effort to help but we’re focusing too much on the specifics. Imagine that such an API exists - how do I tackle it with ReScript? After all, it’s ReScript that I need help wrapping my head around, not some bad API specification!

Just asking because I’ve never come across any API that actually returns an Error object on failure (instead of throwing an exception or returning null or calling an onError handler).

Actually it’s a good pattern in typescript, because this way you can describe possible errors of an API with typesystem. It’s kind of an alternative of result type.

But don’t forget difference between error and exception flow, when use something like this.

For this case, I’d either create a function to test instnanceof Error, or a function to convert it to ReScript’s result type. But you need to use %raw for the instanceof anyway.

1 Like

So basically (in TypeScript terms) type Result<A> = A | Error? OK, I get it. Imho not a great approach (what happens when A is supposed to be Error) but can of course be handled with %raw.

No, in this approach you directly type data or a function return value without creating result type. In this case the code using this approach looks very similar to go, where after every function call you have an if statements, handling possible errors.
To be able to map over result in typescript people usually use a third-party library with either-monad. I personally used sweet-monads/either at master · JSMonk/sweet-monads · GitHub

I’ve never seen such a problem using this approach.

Is --save-dev correct for rescript?

I’m using npm ci --omit=dev when building my docker image and it can’t run because the rescript module doesn’t exist. I think this is an error in the documentation!?

Usually it’s correct to save in dependencies as it has modules which need to be used at runtime. The docs should probably be fixed here.

1 Like

Thanks.

How do I merge two dictionaries in ReScript?

I’m used to doing {…a,…b} but ReScript is only allowing one spread operator it seems.

If you are talking about Js.Dict.t, you would need to write your own binding to Object.assign.

let dictA = [("1", 1), ("2", 2), ("3", 3)]->Js.Dict.fromArray
let dictB = [("4", 4), ("5", 5), ("6", 6)]->Js.Dict.fromArray

@val
external assign: (Js.Dict.t<'a>, Js.Dict.t<'a>) => Js.Dict.t<'a> =
  "Object.assign"

let dict = assign(dictA, dictB)

However, you mostly only need Js.Dict.t for interop with JS libraries.

Prefer using Maps where possible. Belt.Map.String for instance has a merge and a mergeMany method.

Right now, I have (typeless) objects stored in a database. I’m converting them to Js.Dict when loading. Is that a bad idea? How would I convert them to Map?

E.g.

let myMap = myDict->Js.Dict.entries->Belt.Map.String.fromArray

I don’t know if it is a bad idea, but it for sure adds some runtime. What do you mean by convert? Is it just an external or does it produce extra JS code?

1 Like

It’s better to convert these objects into strongly-typed record objects with a schema i.e. the ‘parse, don’t validate’ philosophy.

2 Likes

How can I use ReScript React components from a JSX project? I cannot get it to work and I’m getting all sorts of esoteric errors that I don’t understand.

Nevermind that, I got it to work. However, I cannot do nested components. For example, I like to have Page and Page.Section, but it seems I cannot do that and get it to work in regular JSX

Unless I missed some prior questions, the following should get you a Page and Page.Section components. Of course the outer module Page could also be a Page.res file instead :slight_smile:

module Page = {
  @react.component
  let make = (~children) => <div className={"section"}>{children}</div>

  module Section = {
    @react.component
    let make = (~children) => <div className={"section")>{children}</div>
  }
}

// Usage
<Page><Page.Section>{React.string("Hello")}</Page.Section><Page.Section>{React.string("Subcomponent")}</Page.Section></Page>
1 Like

Thank you.

Yes, but I want to use them from “normal JSX” files. I really don’t, but I have to because Next.js maps file names to routes and under each dir, I need an index.res file and that doesn’t work with ReScript because the filename has to be unique per project, so therefor I’m going to use .jsx files for the pages and ReScript for everything else.