Skip to content

Commit d073e7e

Browse files
author
Basarat Ali Syed
committed
more on useless generics 🌹
1 parent a4fca07 commit d073e7e

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

code/types/generics.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ module aaa {
1717
module bbb {
1818
class QueueNumber {
1919
private data = [];
20-
push = (item:number) => this.data.push(item);
21-
pop = ():number => this.data.shift();
20+
push = (item: number) => this.data.push(item);
21+
pop = (): number => this.data.shift();
2222
}
2323

2424
const queue = new QueueNumber();
@@ -32,8 +32,8 @@ module ccc {
3232
/** A class definition with a generic parameter */
3333
class Queue<T> {
3434
private data = [];
35-
push = (item:T) => this.data.push(item);
36-
pop = ():T => this.data.shift();
35+
push = (item: T) => this.data.push(item);
36+
pop = (): T => this.data.shift();
3737
}
3838

3939
/** Again sample usage */
@@ -43,3 +43,29 @@ module ccc {
4343

4444
// ^ if that error is fixed the rest would be fine too
4545
}
46+
47+
namespace ddd {
48+
const getJSON = <T>(config: {
49+
url: string,
50+
headers?: { [key: string]: string },
51+
}): Promise<T> => {
52+
const fetchConfig = ({
53+
method: 'GET',
54+
'Accept': 'application/json',
55+
'Content-Type': 'application/json',
56+
...(config.headers || {})
57+
});
58+
return fetch(config.url, fetchConfig)
59+
.then<T>(response => response.json());
60+
}
61+
62+
type LoadUsersResponse = {
63+
users: {
64+
name: string;
65+
email: string;
66+
}[];
67+
};
68+
function loadUsers() {
69+
return getJSON<LoadUsersResponse>({ url: 'https://example.com/users' });
70+
}
71+
}

docs/types/generics.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,39 @@ This is just an example, if you are considering on using this `require` typings
176176

177177
1. It's already there in `node.d.ts` you can install using `npm install @types/node --save-dev`.
178178
1. You should consider using the type definitions for your library e.g. for jquery `npm install @types/jquery --save-dev` instead of using raw `require`.
179+
180+
### Caveat: Use generics to make it easier to annotate
181+
182+
The previous example of `require<T>` was intentionally meant to make clear the fact that generics used *only once* are no better than an assertion in terms of type safety. That said they do provide *convenience* to your API.
183+
184+
An example is a function that loads a json response. It returns a promise of *whatever type you pass in*:
185+
```ts
186+
const getJSON = <T>(config: {
187+
url: string,
188+
headers?: { [key: string]: string },
189+
}): Promise<T> => {
190+
const fetchConfig = ({
191+
method: 'GET',
192+
'Accept': 'application/json',
193+
'Content-Type': 'application/json',
194+
...(config.headers || {})
195+
});
196+
return fetch(config.url, fetchConfig)
197+
.then<T>(response => response.json());
198+
}
199+
```
200+
Note that you still have to explicitly annotate what you want, but the `getJSON<T>` signature `(config) => Promise<T>` saves you a few key strokes:
201+
202+
```ts
203+
type LoadUsersResponse = {
204+
users: {
205+
name: string;
206+
email: string;
207+
}[];
208+
}
209+
function loadUsers() {
210+
return getJSON<LoadUsersResponse>({ url: 'https://example.com/users' });
211+
}
212+
```
213+
214+
Also `Promise<T>` as a return value is definitely better than alternatives like `Promise<any>`.

0 commit comments

Comments
 (0)