Exercises answers
Chapter 2: Getting started with TypeScript
Chapters - Table of contents

Scalars

1// 1. add types to the following variables
2//  considering their usage
3
4let username
5username = 'Charly'
6username = null
7// SOLUTION:
8// let username: string  // no need to add `| null`
9
10let hasSubscribed
11hasSubscribed = true
12// let hasSubscribed: boolean
13
14let zipcode
15zipcode = 75000
16zipcode = '75000'
17// SOLUTION:
18// let zipcode: string | number
19
20let distance
21distance = BigInt(9007199254740991)
22distance = undefined
23// SOLUTION:
24// let distance: bigint  // no need to add `| undefined`
25
26// 2. Provide 2 solutions for `coords`
27let coords = [
28  10.23,
29  20.34,
30]
31// SOLUTIONS:
32// coords: [number, number]
33// coords: [lat: number, lng: number]
34
35
36// 3. provide multiple solutions for `position`
37let position
38position = 'left'
39position = 'top'
40position = 'right'
41position = 'bottom'
42
43// SOLUTIONS:
44// let position: 'top' | 'right' | 'bottom' | 'left' = 'top'
45// enum Position {
46//   TOP = 'top'
47//   RIGHT = 'right'
48//   BOTTOM = 'bottom'
49//   LEFT = 'left'
50// }
51// let position: Position = Position.TOP
52
53

Objects

1// 1. Build the proper `Cat` interface for the object below
2
3const cat = {
4  name: 'Meow',
5  nicknames: [
6    'mi',
7    'miaou',
8  ],
9  eats: [
10    'fish',
11    'meat',
12    'cumcumber',
13  ],
14  breed: [
15    'Mushkin',
16    'Persian',
17  ],
18  weight: 4, // in kg
19  family: {
20    id: 1,
21    name: 'Smiths',
22  },
23}
24
25// SOLUTION:
26// interface Cat {
27//  name: string
28//   nicknames: string[]
29//   eats: ('fish' | 'meat' | 'cumcumber')[]
30//   breed: ('Mushkin' | 'Persian' /* and so on ... */)[]
31//   weight: number
32//   family: {
33//     id: number,
34//     name: string
35//   }
36// }
37
38// 2. on the `Cat` interface built, let's add the following
39// behaviors:
40//  - a cat name should be immutable
41//  - a cat might not have a family
42
43// SOLUTION:
44// interface Cat {
45//   readonly name: string
46//   nicknames: string[]
47//   eats: ('fish' | 'meat' | 'cumcumber')[]
48//   breed: ('Mushkin' | 'Persian' /* and so on ... */)[]
49//   weight: number
50//   family?: {
51//     id: number,
52//     name: string
53//   }
54// }
55
56// 3. Let's now consider typing the following dog object:
57
58const dog = {
59  name: 'Dogg',
60  nicknames: [
61    'Doug',
62    'Dougy',
63  ],
64  eats: '*',
65  breed: ['Teckel'],
66  barkingLevel: 5, // backing level from 0 to 10
67  weight: 7, // in kg
68  family: {
69    id: 1,
70    name: 'Smiths',
71  },
72}
73
74// SOLUTION:
75// interface Dog {
76//   name: string
77//   nicknames: string[]
78//   eats: ('fish' | 'meat' | 'cumcumber')[] | '*'
79//   breed: ('Teckel' | 'German Shepherd' /* and so on ... */)[]
80//   weight: number
81//   family: {
82//     id: number,
83//     name: string
84//   }
85// }
86
87// 4. what could we do to avoid code duplication?
88//   Let's create a common `Animal` type
89
90// SOLUTION:
91// interface Family {
92//   id: number,
93//   name: string
94// }
95
96// interface Animal {
97//   readonly name: string
98//   nicknames: string[]
99//   eats: ('fish' | 'meat' | 'cumcumber')[] | '*'
100//   breed: ('Teckel' | 'German Shepherd' | 'Mushkin' | 'Persian' /* and so on ... */)[]
101//   weight: number
102//   family?: Family
103// }
104
105// interface Cat extends Animal {
106//   eats: ('fish' | 'meat' | 'cumcumber')[]
107//   breed: ('Mushkin' | 'Persian')[]
108// }
109
110// interface Dog extends Animal {
111//   eats: ('fish' | 'meat' | 'cumcumber')[] | '*'
112//   breed: ('Teckel' | 'German Shepherd')[]
113// }
114

Functions

1// 1. Type the following `formatDate()` function:
2
3function formatDate(date) {
4  return date.toLocaleString()
5}
6
7// SOLUTION:
8// function formatDate(date: Date): string {
9//   return date.toLocaleString()
10// }
11
12// 2. Type the following component
13
14const Welcome = ({ firstName, lastName }) => (
15  <div>{`Hi ${firstName} ${lastName}!`}</div>
16)
17
18// SOLUTION:
19// interface WelcomeProps {
20//   firstName: string
21//   lastName: string
22// }
23// const Welcome = ({ firstName, lastName }: WelcomeProps) => (
24//   <div>{`Hi ${firstName} ${lastName}!`}</div>
25// )
26
27function Avatar({ avatarUrl }) {
28  return <img src={avatarUrl} alt={'user avatar'} />
29}
30
31// SOLUTION:
32// function Avatar({ avatarUrl }: { avatarUrl: string }) {
33//   return <img src={avatarUrl} alt={'user avatar'} />
34// }
35
36
37// 3. Type the following custom hook
38//  (without looking at the training materials or VSCode higlights 😉)
39
40const useToggle = (defaultValue = false) => {
41  const [value, setValue] = useState(defaultValue)
42
43  return {
44    setToFalse: useCallback(() => {
45      setValue(false)
46    }, [setValue]),
47    setToTrue: useCallback(() => {
48      setValue(true)
49    }, [setValue]),
50    toggle: useCallback(() => {
51      setValue(!value)
52    }, [setValue, value]),
53    value,
54  }
55}
56
57// SOLUTION:
58// interface UseToggleReturnValue {
59//   value: boolean
60//   setToFalse: () => void
61//   setToTrue: () => void
62//   toggle: () => void
63// }
64// 
65// const useToggle = (defaultValue = false): UseToggleReturnValue => {
66//   const [value, setValue] = useState(defaultValue)
67// 
68//   return {
69//     setToFalse: useCallback(() => {
70//       setValue(false)
71//     }, [setValue]),
72//     setToTrue: useCallback(() => {
73//       setValue(true)
74//     }, [setValue]),
75//     toggle: useCallback(() => {
76//       setValue(!value)
77//     }, [setValue, value]),
78//     value,
79//   }
80// }
81
82
83// 4. Provide a type definition of `useToggle()` using `interface`
84
85// SOLUTION:
86// interface UseToggle {
87//
88//  (defaultValue?: boolean): {
89//    value: boolean
90//    setToFalse: () => void
91//    setToTrue: () => void
92//    toggle: () => void
93//  }
94// }
95
96// 5. Type the following component by looking at its props usage
97//  (ignore the <PlanSelector> error)
98
99const SignUpButton = ({
100  user: { firstName },
101  selectedPlan: initialSelectedPlan,
102  onContinue,
103}) => {
104  const [selectedPlan, setSelectedPlan] = useState(initialSelectedPlan)
105  const resetPlan = useCallback(() => {
106    setSelectedPlan(undefined)
107  }, [setSelectedPlan])
108  return (
109    <div>
110      <div></div>
111      <div>
112        {selectedPlan ? (
113          <div>
114            <div>You've choose the "{selectedPlan}" plan</div>
115            <div>
116              <button onClick={resetPlan}>Change plan</button>
117            </div>
118          </div>
119        ) : (
120          <PlanSelector onSelect={setSelectedPlan} />
121        )}
122      </div>
123      <div>
124        <button onClick={onContinue}>Continue</button>
125      </div>
126    </div>
127  )
128}
129
130// SOLUTION:
131// interface SignUpButtonProps {
132//   user: {
133//     firstName: string
134//   }
135//   selectedPlan?: string
136//   onContinue: () => void
137// }
138
139// 6. on the following `Animal` type,
140//  let's add a `eat()` function that takes an aliment type as unique argument
141//   and return if the animal is willing to eat 
142
143interface Family {
144  id: number
145  name: string
146}
147
148interface Animal {
149  readonly name: string
150  nicknames: string[]
151  eats: ('fish' | 'meat' | 'cumcumber')[] | '*'
152  breed: (
153    | 'Teckel'
154    | 'German Shepherd'
155    | 'Mushkin'
156    | 'Persian' /* and so on ... */
157  )[]
158  weight: number
159  family?: Family
160}
161
162// SOLUTION:
163// interface Animal {
164//   readonly name: string
165//   nicknames: string[]
166//   eats: ('fish' | 'meat' | 'cumcumber')[] | '*'
167//   breed: (
168//     | 'Teckel'
169//     | 'German Shepherd'
170//     | 'Mushkin'
171//     | 'Persian' /* and so on ... */
172//   )[]
173//   weight: number
174//   family?: Family
175//   eat: (food: ('fish' | 'meat' | 'cumcumber')) => boolean
176// }
177
178// 7. Let's type the following function
179//    Hint: for this example, we only deal with array of `number`
180//          `iterator` function is expected to return `number[]`
181
182function arrayMap(iterator) {
183  return (array: number[]) => array.map(iterator)
184}
185
186const plusOne = arrayMap((item) => item + 1)
187
188console.log(plusOne([1, 2, 3])) // => [2, 3, 4]
189
190// SOLUTION:
191// function arrayMap(iterator: (arr: number) => number[]) {
192//   return (array: number[]) => array.map(iterator)
193// }
194

Problems

1// what's wrong with this example?
2//   make a change to remove the error
3const myVar = 'string'
4
5if (myVar === 'Charly') {
6  console.log(
7    'hi Charly!'
8  )
9}
10
11// SOLUTION:
12// const myVar: string = 'string'
13
14// if (myVar === 'Charly') {
15//   console.log(
16//     'hi Charly!'
17//   )
18// }
19
20// what's wrong with this example?
21//   make a change to remove the error
22interface Animal {
23  name: string
24}
25
26const animal: Animal = {
27  name: null,
28  age: 10,
29}
30
31// SOLUTION:
32// interface Animal {
33//   name: string
34//   age: number
35// }
36
37// const animal: Animal = {
38//   name: null,
39//   age: 10,
40// }
41
42
43// what's wrong with this example?
44//   make a change to remove the error
45
46interface Family {
47  id: number
48  name: string
49}
50
51interface DomesticAnimal {
52  readonly name: string
53  nicknames: string[]
54  eats:
55    | (
56        | 'fish'
57        | 'meat'
58        | 'cumcumber'
59      )[]
60    | '*'
61  breed: (
62    | 'Teckel'
63    | 'German Shepherd'
64    | 'Mushkin'
65    | 'Persian' /* and so on ... */
66  )[]
67  weight: number
68  family?: Family
69}
70
71interface Cat
72  extends DomesticAnimal {
73  name: number
74  breed: (
75    | 'Mushkin'
76    | 'Persian'
77  )[]
78}
79
80// SOLUTION:
81// interface Cat
82//   extends DomesticAnimal {
83//   name: string
84//   breed: (
85//     | 'Mushkin'
86//     | 'Persian'
87//   )[]
88// }
89
90
91
92
93// what's wrong with this example?
94//   make a change to remove the error
95
96const MyComponent = (
97  prop1: string,
98  prop2: string,
99  props3: string
100) => {
101  // ...
102  return <div />
103}
104
105;<MyComponent
106  prop1={''}
107/>
108
109
110// SOLUTION:
111// const MyComponent = (
112//   { prop1, prop2, prop3 }: { prop1: string, prop2: string, prop3: string }
113// ) => {
114//   // ...
115//   return <div />
116// }
117
118// ;<MyComponent
119//   prop1={''}
120//   prop2={''}
121//   prop3={''}
122// />
123
124
125// what's wrong with this example?
126//   make a change to remove the error
127
128interface MyFunction {
129  (arg: number) => {
130    returnProp: string
131    returnFunc: () : void
132  }
133}
134
135// SOLUTION:
136// interface MyFunction {
137//   (arg: number) : {
138//     returnProp: string
139//     returnFunc: () => void
140//   }
141// }
142
143
144// what's wrong with this example?
145//   make a change to remove the error
146
147const testFunction = (array: string[], callback: (): boolean): boolean => {
148  return callback(array)
149}
150
151// SOLUTION:
152// const testFunction = (array: string[], callback: (arr: string[]) => boolean): boolean => {
153//   return callback(array)
154// }
155
156// what's wrong with this example?
157function Avatar({ user: { firstname: boolean, lastName: boolean } }) {
158  return <div />
159}
160
161// SOLUTION:
162// function Avatar({ user: { firstname, lastName } }: { user: { firstname: boolean, lastName: boolean } }) {
163//   return <div />
164// }
165
We use cookies to collect statistics through Google Analytics.
Do not track
 
Allow cookies