Skip to content

Commit afef101

Browse files
committed
add intermediate ts challenges
1 parent 785614c commit afef101

File tree

5 files changed

+378
-0
lines changed

5 files changed

+378
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
8 - Readonly 2
3+
-------
4+
by Anthony Fu (@antfu) #medium #readonly #object-keys
5+
6+
### Question
7+
8+
Implement a generic `MyReadonly2<T, K>` which takes two type argument `T` and `K`.
9+
10+
`K` specify the set of properties of `T` that should set to Readonly. When `K` is not provided, it should make all properties readonly just like the normal `Readonly<T>`.
11+
12+
For example
13+
14+
```ts
15+
interface Todo {
16+
title: string
17+
description: string
18+
completed: boolean
19+
}
20+
21+
const todo: MyReadonly2<Todo, 'title' | 'description'> = {
22+
title: "Hey",
23+
description: "foobar",
24+
completed: false,
25+
}
26+
27+
todo.title = "Hello" // Error: cannot reassign a readonly property
28+
todo.description = "barFoo" // Error: cannot reassign a readonly property
29+
todo.completed = true // OK
30+
```
31+
32+
> View on GitHub: https://tsch.js.org/8
33+
*/
34+
35+
/* _____________ Your Code Here _____________ */
36+
37+
type MyReadonly<T> = { readonly [P in keyof T]: T[P] };
38+
39+
type MyReadonly3<T, K = void> = K extends void
40+
? MyReadonly<T>
41+
: K extends T
42+
? { readonly [P in keyof K]: K[P] }
43+
: {[P in keyof T]: T[P]};
44+
45+
type MyReadonly2<T, K extends keyof T = keyof T> = Omit<T, K> &
46+
Readonly<Pick<T, K>>;
47+
48+
const test: MyReadonly2<Todo2, "title" | "description"> = {
49+
title: 'h',
50+
description: '',
51+
completed: false,
52+
53+
}
54+
55+
const full: MyReadonly2<Todo1> = {
56+
title: "ho",
57+
description: "des",
58+
completed: true,
59+
};
60+
// @ts-expect-error
61+
full.completed = false;
62+
63+
/* _____________ Test Cases _____________ */
64+
import type { Alike, Expect } from "@type-challenges/utils";
65+
66+
type cases = [
67+
Expect<Alike<MyReadonly2<Todo1>, Readonly<Todo1>>>,
68+
Expect<Alike<MyReadonly2<Todo1, "title" | "description">, Expected>>,
69+
Expect<Alike<MyReadonly2<Todo2, "title" | "description">, Expected>>,
70+
Expect<Alike<MyReadonly2<Todo2, "description">, Expected>>,
71+
Expect<Alike<MyReadonly2<Todo1>, Full>>
72+
];
73+
74+
// @ts-expect-error
75+
type error = MyReadonly2<Todo1, "title" | "invalid">;
76+
77+
interface Todo1 {
78+
title: string;
79+
description?: string;
80+
completed: boolean;
81+
}
82+
83+
interface Todo2 {
84+
readonly title: string;
85+
description?: string;
86+
completed: boolean;
87+
}
88+
89+
interface Expected {
90+
readonly title: string;
91+
readonly description?: string;
92+
completed: boolean;
93+
}
94+
95+
interface Full {
96+
readonly title: string;
97+
readonly description?: string;
98+
readonly completed: boolean;
99+
}
100+
101+
/* _____________ Further Steps _____________ */
102+
/*
103+
> Share your solutions: https://tsch.js.org/8/answer
104+
> View solutions: https://tsch.js.org/8/solutions
105+
> More Challenges: https://tsch.js.org
106+
*/
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
9 - Deep Readonly
3+
-------
4+
by Anthony Fu (@antfu) #medium #readonly #object-keys #deep
5+
6+
### Question
7+
8+
Implement a generic `DeepReadonly<T>` which make every parameter of an object - and its sub-objects recursively - readonly.
9+
10+
You can assume that we are only dealing with Objects in this challenge. Arrays, Functions, Classes and so on do not need to be taken into consideration. However, you can still challenge yourself by covering as many different cases as possible.
11+
12+
For example:
13+
14+
```ts
15+
type X = {
16+
x: {
17+
a: 1
18+
b: 'hi'
19+
}
20+
y: 'hey'
21+
}
22+
23+
type Expected = {
24+
readonly x: {
25+
readonly a: 1
26+
readonly b: 'hi'
27+
}
28+
readonly y: 'hey'
29+
}
30+
31+
type Todo = DeepReadonly<X> // should be same as `Expected`
32+
```
33+
34+
> View on GitHub: https://tsch.js.org/9
35+
*/
36+
37+
/* _____________ Your Code Here _____________ */
38+
39+
type DeepReadonly<T> = T extends Function
40+
? T
41+
: T extends object
42+
? {
43+
readonly [P in keyof T]: DeepReadonly<T[P]>;
44+
}
45+
: T;
46+
47+
type X = {
48+
x: {
49+
a: 1;
50+
b: "hi";
51+
};
52+
y: "hey";
53+
};
54+
55+
type Expected = {
56+
readonly x: {
57+
readonly a: 1;
58+
readonly b: "hi";
59+
};
60+
readonly y: "hey";
61+
};
62+
type Todo = DeepReadonly<X>; // should be same as `Expected`
63+
64+
/* _____________ Test Cases _____________ */
65+
import type { Equal, Expect } from "@type-challenges/utils";
66+
67+
type cases = [
68+
Expect<Equal<DeepReadonly<X1>, Expected1>>,
69+
Expect<Equal<DeepReadonly<X2>, Expected2>>,
70+
Expect<Equal<DeepReadonly<Todo>, Expected>>
71+
];
72+
73+
type X1 = {
74+
a: () => 22;
75+
b: string;
76+
c: {
77+
d: boolean;
78+
e: {
79+
g: {
80+
h: {
81+
i: true;
82+
j: "string";
83+
};
84+
k: "hello";
85+
};
86+
l: [
87+
"hi",
88+
{
89+
m: ["hey"];
90+
}
91+
];
92+
};
93+
};
94+
};
95+
96+
type X2 = { a: string } | { b: number };
97+
98+
type Expected1 = {
99+
readonly a: () => 22;
100+
readonly b: string;
101+
readonly c: {
102+
readonly d: boolean;
103+
readonly e: {
104+
readonly g: {
105+
readonly h: {
106+
readonly i: true;
107+
readonly j: "string";
108+
};
109+
readonly k: "hello";
110+
};
111+
readonly l: readonly [
112+
"hi",
113+
{
114+
readonly m: readonly ["hey"];
115+
}
116+
];
117+
};
118+
};
119+
};
120+
121+
type Expected2 = { readonly a: string } | { readonly b: number };
122+
123+
/* _____________ Further Steps _____________ */
124+
/*
125+
> Share your solutions: https://tsch.js.org/9/answer
126+
> View solutions: https://tsch.js.org/9/solutions
127+
> More Challenges: https://tsch.js.org
128+
*/
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
10 - Tuple to Union
3+
-------
4+
by Anthony Fu (@antfu) #medium #infer #tuple #union
5+
6+
### Question
7+
8+
Implement a generic `TupleToUnion<T>` which covers the values of a tuple to its values union.
9+
10+
For example
11+
12+
```ts
13+
type Arr = ['1', '2', '3']
14+
15+
type Test = TupleToUnion<Arr> // expected to be '1' | '2' | '3'
16+
```
17+
18+
> View on GitHub: https://tsch.js.org/10
19+
*/
20+
21+
/* _____________ Your Code Here _____________ */
22+
23+
type TupleToUnion<T extends any[]> = T[number];
24+
type Arr = ["1", "2", "3"];
25+
26+
type Test = TupleToUnion<Arr>; // expected to be '1' | '2' | '3'
27+
28+
/* _____________ Test Cases _____________ */
29+
import type { Equal, Expect } from "@type-challenges/utils";
30+
31+
type cases = [
32+
Expect<Equal<TupleToUnion<[123, "456", true]>, 123 | "456" | true>>,
33+
Expect<Equal<TupleToUnion<[123]>, 123>>
34+
];
35+
36+
/* _____________ Further Steps _____________ */
37+
/*
38+
> Share your solutions: https://tsch.js.org/10/answer
39+
> View solutions: https://tsch.js.org/10/solutions
40+
> More Challenges: https://tsch.js.org
41+
*/
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
15 - Last of Array
3+
-------
4+
by Anthony Fu (@antfu) #medium #array
5+
6+
### Question
7+
8+
> TypeScript 4.0 is recommended in this challenge
9+
10+
Implement a generic `Last<T>` that takes an Array `T` and returns its last element.
11+
12+
For example
13+
14+
```ts
15+
type arr1 = ['a', 'b', 'c']
16+
type arr2 = [3, 2, 1]
17+
18+
type tail1 = Last<arr1> // expected to be 'c'
19+
type tail2 = Last<arr2> // expected to be 1
20+
```
21+
22+
> View on GitHub: https://tsch.js.org/15
23+
*/
24+
25+
/* _____________ Your Code Here _____________ */
26+
27+
type Last<T extends any[]> = ["dummy",...T][T["length"]];
28+
type arr1 = ["a", "b", "c"];
29+
type arr2 = [3, 2, 1];
30+
31+
type tail1 = Last<arr1>; // expected to be 'c'
32+
type tail2 = Last<arr2>; // expected to be 1
33+
34+
/* _____________ Test Cases _____________ */
35+
import type { Equal, Expect } from "@type-challenges/utils";
36+
37+
type cases = [
38+
Expect<Equal<Last<[2]>, 2>>,
39+
Expect<Equal<Last<[3, 2, 1]>, 1>>,
40+
Expect<Equal<Last<[() => 123, { a: string }]>, { a: string }>>
41+
];
42+
43+
/* _____________ Further Steps _____________ */
44+
/*
45+
> Share your solutions: https://tsch.js.org/15/answer
46+
> View solutions: https://tsch.js.org/15/solutions
47+
> More Challenges: https://tsch.js.org
48+
*/
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
16 - Pop
3+
-------
4+
by Anthony Fu (@antfu) #medium #array
5+
6+
### Question
7+
8+
> TypeScript 4.0 is recommended in this challenge
9+
10+
Implement a generic `Pop<T>` that takes an Array `T` and returns an Array without it's last element.
11+
12+
For example
13+
14+
```ts
15+
type arr1 = ['a', 'b', 'c', 'd']
16+
type arr2 = [3, 2, 1]
17+
18+
type re1 = Pop<arr1> // expected to be ['a', 'b', 'c']
19+
type re2 = Pop<arr2> // expected to be [3, 2]
20+
```
21+
22+
**Extra**: Similarly, can you implement `Shift`, `Push` and `Unshift` as well?
23+
24+
> View on GitHub: https://tsch.js.org/16
25+
*/
26+
27+
/* _____________ Your Code Here _____________ */
28+
29+
type Pop<T extends any[]> = T extends []
30+
? []
31+
: T extends [...infer P, infer _]
32+
? P
33+
: never;
34+
35+
type arr1 = ["a", "b", "c", "d"];
36+
type arr2 = [3, 2, 1];
37+
38+
type re1 = Pop<arr1>; // expected to be ['a', 'b', 'c']
39+
type re2 = Pop<arr2>; // expected to be [3, 2]
40+
41+
/* _____________ Test Cases _____________ */
42+
import type { Equal, Expect } from "@type-challenges/utils";
43+
44+
type cases = [
45+
Expect<Equal<Pop<[3, 2, 1]>, [3, 2]>>,
46+
Expect<Equal<Pop<["a", "b", "c", "d"]>, ["a", "b", "c"]>>,
47+
Expect<Equal<Pop<[]>, []>>
48+
];
49+
50+
/* _____________ Further Steps _____________ */
51+
/*
52+
> Share your solutions: https://tsch.js.org/16/answer
53+
> View solutions: https://tsch.js.org/16/solutions
54+
> More Challenges: https://tsch.js.org
55+
*/

0 commit comments

Comments
 (0)