Skip to content

Commit 11f43e4

Browse files
authored
fix: add typescript usage instructions (#45)
1 parent a44bf76 commit 11f43e4

File tree

2 files changed

+68
-43
lines changed

2 files changed

+68
-43
lines changed

README.md

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Simplify your async `useEffect` code with a [generator function](https://develop
1010
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
1111
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
1212

13-
1413
- [The problem](#the-problem)
1514
- [Example](#example)
1615
- [Before 😖](#before-)
@@ -20,8 +19,9 @@ Simplify your async `useEffect` code with a [generator function](https://develop
2019
- [Usage Instructions](#usage-instructions)
2120
- [Basic Usage](#basic-usage)
2221
- [Cancelling an in-flight `fetch` request](#cancelling-an-in-flight-fetch-request)
23-
- [Clean-Up Handler](#cleanup-handler)
22+
- [Cleanup Handler](#cleanup-handler)
2423
- [Setup eslint for `eslint-plugin-react-hooks`](#setup-eslint-for-eslint-plugin-react-hooks)
24+
- [Usage with TypeScript](#usage-with-typescript)
2525
- [API](#api)
2626
- [`useAsyncEffect`](#useasynceffect)
2727
- [Contributing](#contributing)
@@ -103,7 +103,6 @@ const MyComponent = ({ filter }) => {
103103
[filter]
104104
);
105105
};
106-
107106
```
108107

109108
## Usage
@@ -128,15 +127,12 @@ import useAsyncEffect from "@n1ru4l/use-async-effect";
128127

129128
const MyDoggoImage = () => {
130129
const [doggoImageSrc, setDoggoImageSrc] = useState(null);
131-
useAsyncEffect(
132-
function*() {
133-
const { message } = yield fetch(
134-
"https://dog.ceo/api/breeds/image/random"
135-
).then(res => res.json());
136-
setDoggoImageSrc(message);
137-
},
138-
[]
139-
);
130+
useAsyncEffect(function*() {
131+
const { message } = yield fetch(
132+
"https://dog.ceo/api/breeds/image/random"
133+
).then(res => res.json());
134+
setDoggoImageSrc(message);
135+
}, []);
140136

141137
return doggoImageSrc ? <img src={doggoImageSrc} /> : null;
142138
};
@@ -155,20 +151,16 @@ import useAsyncEffect from "@n1ru4l/use-async-effect";
155151

156152
const MyDoggoImage = () => {
157153
const [doggoImageSrc, setDoggoImageSrc] = useState(null);
158-
useAsyncEffect(
159-
function*(onCancel) {
160-
const abortController = new AbortController();
161-
onCancel(() => {
162-
abortController.abort();
163-
});
164-
const { message } = yield fetch(
165-
"https://dog.ceo/api/breeds/image/random",
166-
{ signal: abortController.signal }
167-
);
168-
setDoggoImageSrc(message);
169-
},
170-
[]
171-
);
154+
useAsyncEffect(function*(onCancel) {
155+
const abortController = new AbortController();
156+
onCancel(() => {
157+
abortController.abort();
158+
});
159+
const { message } = yield fetch("https://dog.ceo/api/breeds/image/random", {
160+
signal: abortController.signal
161+
});
162+
setDoggoImageSrc(message);
163+
}, []);
172164

173165
return doggoImageSrc ? <img src={doggoImageSrc} /> : null;
174166
};
@@ -184,21 +176,16 @@ import useAsyncEffect from "@n1ru4l/use-async-effect";
184176

185177
const MyDoggoImage = () => {
186178
const [doggoImageSrc, setDoggoImageSrc] = useState(null);
187-
useAsyncEffect(
188-
function*() {
189-
const { message } = yield fetch(
190-
"https://dog.ceo/api/breeds/image/random"
191-
);
192-
setDoggoImageSrc(message);
193-
194-
const listener = () => {
195-
console.log("I LOVE DOGGIES", message);
196-
};
197-
window.addEventListener("mousemove", listener);
198-
return () => window.removeEventListener("mousemove", listener);
199-
},
200-
[]
201-
);
179+
useAsyncEffect(function*() {
180+
const { message } = yield fetch("https://dog.ceo/api/breeds/image/random");
181+
setDoggoImageSrc(message);
182+
183+
const listener = () => {
184+
console.log("I LOVE DOGGIES", message);
185+
};
186+
window.addEventListener("mousemove", listener);
187+
return () => window.removeEventListener("mousemove", listener);
188+
}, []);
202189

203190
return doggoImageSrc ? <img src={doggoImageSrc} /> : null;
204191
};
@@ -225,6 +212,43 @@ Add the following to your eslint config file:
225212
}
226213
```
227214

215+
#### Usage with TypeScript
216+
217+
Unfortunately, it is currently not possible to [to interfer the type of a yield expression based on the yielded value](https://github.com/microsoft/TypeScript/issues/32523).
218+
However, there is a workaround for typing yielded results.
219+
220+
```tsx
221+
useAsyncEffect(function*() {
222+
// without the type annotation `numericValue` would be of the type `any`
223+
const numericValue: number = yield Promise.resolve(123);
224+
});
225+
```
226+
227+
For complex use cases you can leverage some TypeScript utility types ([based on Conditional Types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types)):
228+
229+
```tsx
230+
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;
231+
232+
useAsyncEffect(function*() {
233+
const promise = fetchSomeData();
234+
const result: ThenArg<typeof promise> = yield promise;
235+
});
236+
```
237+
238+
Or the "shorter version" (less variable assignments):
239+
240+
```tsx
241+
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;
242+
243+
useAsyncEffect(function*() {
244+
const result: ThenArg<ReturnType<
245+
typeof fetchSomeData
246+
>> = yield fetchSomeData();
247+
});
248+
```
249+
250+
This is no ideal solution (and indeed prone to errors, due to typos or wrong type casting). However, it is still a bitter solution than go without types at all. In the future TypeScript might be able to improve the current situation.
251+
228252
## API
229253

230254
### `useAsyncEffect`

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,17 @@
6666
}
6767
},
6868
"lint-staged": {
69-
"*.{yml,ts,tsx,js,json,md}": [
69+
"*.{yml,ts,tsx,js,json}": [
7070
"prettier --write",
7171
"git add"
7272
],
7373
"*.{ts,tsx,js}": [
7474
"eslint",
7575
"git add"
7676
],
77-
"README.md": [
77+
"*.md": [
7878
"doctoc",
79+
"prettier --write",
7980
"git add"
8081
]
8182
}

0 commit comments

Comments
 (0)