Skip to content

Commit 1bca6c0

Browse files
committed
Added const generics instructions
1 parent f5fc11d commit 1bca6c0

9 files changed

+42
-68
lines changed

notes/FUTURE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ With a non-generic external library
6767
### 6. Identity Functions
6868

6969
✅ No generics on objects!
70-
✅ F.Narrow vs as const
7170
✅ F.NoInfer
7271
✅ Lodash (MAYBE REVISIT AND ADD COMPLEXITY)
7372

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@types/node": "^18.6.5",
99
"chokidar": "^3.5.3",
1010
"cross-fetch": "^3.1.5",
11-
"typescript": "^4.8.3",
11+
"typescript": "^5.0.2",
1212
"vitest": "^0.21.1"
1313
},
1414
"scripts": {
Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
11
import { Equal, Expect } from "../helpers/type-utils";
22

3-
/**
4-
* This is an identity function. It takes a value and returns the same value.
5-
* Except that it doesn't work great on arrays, or object values.
6-
*
7-
* Below, you can see that fruits is typed as
8-
*
9-
* { name: string; price: number }[]
10-
*
11-
* instead of [{ name: "apple"; price: 1 }, { name: "banana"; price: 2 }]
12-
*
13-
* We could handle this using 'as const', but sometimes that isn't possible.
14-
*
15-
* So, we can use F.Narrow from ts-toolbelt instead.
16-
*/
173
export const asConst = <T>(t: T) => t;
184

195
const fruits = asConst([
@@ -31,16 +17,16 @@ type tests = [
3117
Expect<
3218
Equal<
3319
typeof fruits,
34-
[
20+
readonly [
3521
{
36-
name: "apple";
37-
price: 1;
22+
readonly name: "apple";
23+
readonly price: 1;
3824
},
3925
{
40-
name: "banana";
41-
price: 2;
42-
},
26+
readonly name: "banana";
27+
readonly price: 2;
28+
}
4329
]
4430
>
45-
>,
31+
>
4632
];

src/06-identity-functions/27-as-const-alternative.solution.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { F } from "ts-toolbelt";
21
import { Equal, Expect } from "../helpers/type-utils";
32

4-
export const asConst = <T>(t: F.Narrow<T>) => t;
3+
export const asConst = <const T>(t: T) => t;
54

65
/**
76
* Now, fruits is typed as:
@@ -25,16 +24,16 @@ type tests = [
2524
Expect<
2625
Equal<
2726
typeof fruits,
28-
[
27+
readonly [
2928
{
30-
name: "apple";
31-
price: 1;
29+
readonly name: "apple";
30+
readonly price: 1;
3231
},
3332
{
34-
name: "banana";
35-
price: 2;
36-
},
33+
readonly name: "banana";
34+
readonly price: 2;
35+
}
3736
]
3837
>
39-
>,
38+
>
4039
];

src/06-identity-functions/28-constraints-with-f.narrow.problem.ts renamed to src/06-identity-functions/28-constraints-with-const-generics.problem.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
import { F } from "ts-toolbelt";
21
import { it } from "vitest";
32
import { Equal, Expect } from "../helpers/type-utils";
43

5-
/**
6-
* We know that asConst works, but we now also want to be
7-
* able to narrow the type to only allow an array
8-
* of fruits.
9-
*/
104
export const narrowFruits = <TFruits>(t: TFruits) => t;
115

126
const fruits = narrowFruits([
@@ -24,14 +18,14 @@ type tests = [
2418
Expect<
2519
Equal<
2620
typeof fruits,
27-
[
21+
readonly [
2822
{
29-
name: "apple";
30-
price: 1;
23+
readonly name: "apple";
24+
readonly price: 1;
3125
},
3226
{
33-
name: "banana";
34-
price: 2;
27+
readonly name: "banana";
28+
readonly price: 2;
3529
}
3630
]
3731
>

src/06-identity-functions/28-constraints-with-f.narrow.solution.ts renamed to src/06-identity-functions/28-constraints-with-const-generics.solution.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { F } from "ts-toolbelt";
21
import { it } from "vitest";
32
import { Equal, Expect } from "../helpers/type-utils";
43

5-
export const narrowFruits = <TFruits extends { name: string; price: number }[]>(
6-
t: F.Narrow<TFruits>,
4+
export const narrowFruits = <const TFruits extends readonly { name: string; price: number }[]>(
5+
t: TFruits,
76
) => t;
87

98
const fruits = narrowFruits([
@@ -21,14 +20,14 @@ type tests = [
2120
Expect<
2221
Equal<
2322
typeof fruits,
24-
[
23+
readonly [
2524
{
26-
name: "apple";
27-
price: 1;
25+
readonly name: "apple";
26+
readonly price: 1;
2827
},
2928
{
30-
name: "banana";
31-
price: 2;
29+
readonly name: "banana";
30+
readonly price: 2;
3231
},
3332
]
3433
>

src/07-challenges/32-narrow-with-arrays.problem.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ interface Fruit {
66
}
77

88
export const wrapFruit = (fruits: unknown[]) => {
9-
const getFruit = (name: unknown): unknown => {
9+
const getFruit = (name: unknown) => {
1010
return fruits.find((fruit) => fruit.name === name);
1111
};
1212

@@ -32,6 +32,6 @@ const apple = fruits.getFruit("apple");
3232
const notAllowed = fruits.getFruit("not-allowed");
3333

3434
type tests = [
35-
Expect<Equal<typeof apple, { name: "apple"; price: 1 }>>,
36-
Expect<Equal<typeof banana, { name: "banana"; price: 2 }>>,
35+
Expect<Equal<typeof apple, { readonly name: "apple"; readonly price: 1 }>>,
36+
Expect<Equal<typeof banana, { readonly name: "banana"; readonly price: 2 }>>
3737
];

src/07-challenges/32-narrow-with-arrays.solution.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import { Equal, Expect } from "../helpers/type-utils";
2-
import { F } from "ts-toolbelt";
32

43
interface Fruit {
54
name: string;
65
price: number;
76
}
87

9-
export const wrapFruit = <TFruits extends Fruit[]>(
10-
fruits: F.Narrow<TFruits>
11-
) => {
8+
export const wrapFruit = <const TFruits extends readonly Fruit[]>(fruits: TFruits) => {
129
const getFruit = <TName extends TFruits[number]["name"]>(name: TName) => {
1310
return fruits.find((fruit) => fruit.name === name) as Extract<
1411
TFruits[number],
@@ -38,6 +35,6 @@ const apple = fruits.getFruit("apple");
3835
const notAllowed = fruits.getFruit("not-allowed");
3936

4037
type tests = [
41-
Expect<Equal<typeof apple, { name: "apple"; price: 1 }>>,
42-
Expect<Equal<typeof banana, { name: "banana"; price: 2 }>>
38+
Expect<Equal<typeof apple, { readonly name: "apple"; readonly price: 1 }>>,
39+
Expect<Equal<typeof banana, { readonly name: "banana"; readonly price: 2 }>>
4340
];

0 commit comments

Comments
 (0)