Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f3d7150

Browse files
committedMay 2, 2024·
add another example
1 parent ec753ff commit f3d7150

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed
 

‎pages/docs/manual/latest/module-functions.mdx

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@ canonical: "/docs/manual/latest/module-functions"
66

77
# Module Functions
88

9+
Module functions can be used to create modules based on types, values, or functions from other modules.
10+
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.
11+
12+
Next.js has a `useNavigation` hook that returns an unknown type,
13+
and it's up to the developer to add in a type annotation to define the type of the parameters returned by the hook.
14+
```TS
15+
const params = useParams<{ tag: string; item: string }>()
16+
```
17+
18+
Instead of having to add the type annotation every time you use the hook, you can create a module function that will return a typed response for the `useNavigation` hook.
919
<CodeTab labels={["ReScript", "JS Output"]}>
1020
```res example
1121
module Next = {
12-
// define a module type to use a parameter for out module function
13-
module type Params = {
14-
type t
15-
}
16-
1722
// define our module function
18-
module MakeNavigation = (Params: Params) => {
23+
module MakeNavigation = (Params: { type t }) => {
1924
@module("next/navigation")
2025
external useNavigation: unit => Params.t = "useNavigation"
2126
/* You can use values from the function parameter, such as Params.t */
@@ -88,5 +93,56 @@ export {
8893
}
8994
/* next/navigation Not a pure module */
9095

96+
```
97+
</ CodeTab>
98+
99+
This becomes incredibly useful when you need to have types that are unique to a project but shared across multiple components.
100+
Let's say you want to create a library with a `useEnv` hook to load in environment variables found in `import.meta.env`.
101+
```res
102+
@val external env: 'a = "import.meta.env"
103+
104+
let useEnv = () => {
105+
env
106+
}
107+
```
108+
It's not possible to define types for this that will work for every project, so we just set it as 'a and the consumer of our library can define the return type when they use the hook.
109+
```res
110+
type t = {"LOG_LEVEL": string}
111+
112+
let values: t = useEnv()
113+
```
114+
This isn't great and it doesn't take advantage of ReScript's type system and ability to use types without type definitions, and it can't be easily shared across our application.
115+
116+
We can instead create a module function that can return a module that has contains a `useEnv` hook that has a typed response.
117+
```res
118+
module MakeEnv = (
119+
E: {
120+
type t
121+
},
122+
) => {
123+
@val external env: E.t = "import.meta.env"
124+
125+
let useEnv = () => {
126+
env
127+
}
128+
}
129+
```
130+
And now consumers of our library can define the types and create a custom version of the hook just for their application.
131+
Notice that in the JavaScript output that the `import.meta.env` is used directly and doesn't require any function calls or runtime overhead.
132+
133+
<CodeTab labels={["ReScript", "JS Output"]}>
134+
```res
135+
module Env = MakeEnv({
136+
type t = {"LOG_LEVEL": string}
137+
})
138+
139+
let values = Env.useEnv()
140+
```
141+
```js
142+
var Env = {
143+
useEnv: useEnv
144+
};
145+
146+
var values = import.meta.env;
91147
```
92148
</ CodeTab>

0 commit comments

Comments
 (0)
Please sign in to comment.