Skip to content

Commit

Permalink
more module function examples
Browse files Browse the repository at this point in the history
  • Loading branch information
jderochervlk committed May 2, 2024
1 parent f3d7150 commit 8f7072f
Showing 1 changed file with 162 additions and 1 deletion.
163 changes: 162 additions & 1 deletion pages/docs/manual/latest/module-functions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ canonical: "/docs/manual/latest/module-functions"
Module functions can be used to create modules based on types, values, or functions from other modules.
This is a powerful tool that can be used to created abstractions and reusable code that might not be possible with functions, or might have a runtime cost if done with functions.

## Quick example
Next.js has a `useNavigation` hook that returns an unknown type,
and it's up to the developer to add in a type annotation to define the type of the parameters returned by the hook.
```TS
Expand Down Expand Up @@ -96,6 +97,7 @@ export {
```
</ CodeTab>

## Sharing a type with an external binding
This becomes incredibly useful when you need to have types that are unique to a project but shared across multiple components.
Let's say you want to create a library with a `useEnv` hook to load in environment variables found in `import.meta.env`.
```res
Expand Down Expand Up @@ -145,4 +147,163 @@ var Env = {

var values = import.meta.env;
```
</ CodeTab>
</ CodeTab>

## Shared functions
You might want to share functions across modules, like a way to log a value or render it in React.
Here's an example of module function that takes in a type and a transform to string function.

```res
module MakeDataModule = (
T: {
type t
let toString: t => string
},
) => {
type t = T.t
let log = a => Console.log("The value is " ++ T.toString(a))
module Render = {
@react.component
let make = (~value) => value->T.toString->React.string
}
}
```
You can now take a module with a type of `t` and a `toString` function and create a new module that has the `log` function and the `Render` component.
<CodeTab labels={["ReScript", "JS Output"]}>
```res
module Person = {
type t = { firstName: string, lastName: string }
let toString = person => person.firstName ++ person.lastName
}
module PersonData = MakeDataModule(Person)
```

```js
// Notice that none of the JS output references the MakeDataModule function

function toString(person) {
return person.firstName + person.lastName;
}

var Person = {
toString: toString
};

function log(a) {
console.log("The value is " + toString(a));
}

function Person$MakeDataModule$Render(props) {
return toString(props.value);
}

var Render = {
make: Person$MakeDataModule$Render
};

var PersonData = {
log: log,
Render: Render
};
```
</CodeTab>

Now the `PersonData` module has the functions from the `MakeDataModule`.
<CodeTab labels={["ReScript", "JS Output"]}>
```res
@react.component
let make = (~person) => {
let handleClick = _ => PersonData.log(person)
<div>
{React.string("Hello ")}
<PersonData.Render value=person />
<button onClick=handleClick>
{React.string("Log value to console")}
</button>
</div>
}
```
```js
function Person$1(props) {
var person = props.person;
var handleClick = function (param) {
log(person);
};
return JsxRuntime.jsxs("div", {
children: [
"Hello ",
JsxRuntime.jsx(Person$MakeDataModule$Render, {
value: person
}),
JsxRuntime.jsx("button", {
children: "Log value to console",
onClick: handleClick
})
]
});
}
```
</CodeTab>

## Dependency injection
Module functions can be used for dependency injection.
Here's an example of injecting in a some config values into a set of functions to access a database.
<CodeTab labels={["ReScript", "JS Output"]}>
```res
module type DbConfig = {
let host: string
let database: string
let username: string
let password: string
}
module MakeDbConnection = (Config: DbConfig) => {
type client = {
write: string => unit,
read: string => string,
}
@module("database.js")
external makeClient: (string, string, string, string) => client = "makeClient"
let client = makeClient(Config.host, Config.database, Config.username, Config.password)
}
module Db = MakeDbConnection({
let host = "localhost"
let database = "mydb"
let username = "root"
let password = "password"
})
let updateDb = Db.client.write("new value")
```
```js
// Generated by ReScript, PLEASE EDIT WITH CARE

import * as DatabaseJs from "database.js";

function MakeDbConnection(Config) {
var client = DatabaseJs.makeClient(Config.host, Config.database, Config.username, Config.password);
return {
client: client
};
}

var client = DatabaseJs.makeClient("localhost", "mydb", "root", "password");

var Db = {
client: client
};

var updateDb = client.write("new value");

export {
MakeDbConnection ,
Db ,
updateDb ,
}
/* client Not a pure module */
```
</CodeTab>

0 comments on commit 8f7072f

Please sign in to comment.