Exercises answers - Part 1
Chapter 3: TypeScript for real-world applications
Chapters - Table of contents

Function overloads

1////////////////////////////////////////
2// 1. Type the following function by looking at its body and usage
3
4function formatDate(date, format = 'dd-mm-YYYY') {
5  let d = null
6  if (typeof date === 'string') {
7    d = parseISO(date)
8  } else if (typeof date === 'number') {
9    d = new Date(date)
10  } else if (date instanceof Date) {
11    d = date
12  } else {
13    return null
14  }
15  if (d.toString() === 'Invalid Date') {
16    return null
17  } else {
18    return fmtDate(d, format)
19  }
20}
21
22// SOLUTION:
23// function formatDate(
24//   date: Date | string | number,
25//   format = 'dd-mm-YYYY'
26// ): string | null {
27//   let d = null
28//   if (typeof date === 'string') {
29//     d = parseISO(date)
30//   } else if (typeof date === 'number') {
31//     d = new Date(date)
32//   } else if (date instanceof Date) {
33//     d = date
34//   } else {
35//     return null
36//   }
37//   if (d.toString() === 'Invalid Date') {
38//     return null
39//   } else {
40//     return fmtDate(d, format)
41//   }
42// }
43
44////////////////////////////////////////
45// 2. Type the following function by looking at:
46//  - its body
47//  - the types defined for the different types of `Post`
48
49interface Post {
50  id: string
51  createdAt: Date
52  updatedAt: Date
53  description: string
54  title: string
55  type: 'engineering' | 'corporate'
56}
57
58interface PostEngineering extends Post {
59  type: 'engineering'
60  technologies: ('ruby' | 'javascript')[]
61  githubLink: string
62}
63
64interface PostCorporate extends Post {
65  type: 'corporate'
66  tags: string[]
67  linkedArticles: string[]
68}
69
70// `type` can either be 'engineering' or 'corporate'.
71function filterPostByType(posts, type = 'corporate') {
72  return posts.filter((p) => p.type === type)
73}
74
75// SOLUTION:
76// function filterPostByType(posts: Post[], type: 'corporate'): PostCorporate[];
77// function filterPostByType(posts: Post[], type: 'engineering'): PostEngineering[];
78// function filterPostByType(posts: Post[], type: 'engineering' | 'corporate'): any[] {
79//   return posts.filter(p => p.type === type)
80// }
81
82////////////////////////////////////////
83// 3. Rewrite the correct type definition of `useRef()` with the following types and
84//    usage examples
85
86// SOLUTION: 
87// interface RefObject {
88//   readonly current: any
89// }
90
91// interface MutableRefObject {
92//   current: any
93// }
94
95// interface UseRef {
96//   (initialValue: any): RefObject;
97//   (): MutableRefObject;
98// }
99
100// const useRef: UseRef = (ref?: any): MutableRefObject | RefObject => {
101//   return {
102//     current: null
103//   }
104// }
105

Generics

1////////////////////////////////////////
2// 1. Type the following custom hook by looking at its body and usage:
3
4// keeps a localstorage value in sync with React state
5const useStorage = (name, initialValue = {}) => {
6  const [value, setValue] = useState(initialValue)
7
8  useEffect(() => {
9    const t = setTimeout(() => {
10      if (value !== localStorage.getItem(name)) {
11        setValue(JSON.parse(localStorage.getItem(name) || '{}'))
12      }
13    }, 500)
14    return () => clearTimeout(t)
15  })
16
17  const update = useCallback(
18    (val) => {
19      localStorage.setItem(name, JSON.stringify(val || '{}'))
20      setValue(val)
21    },
22    [name, setValue]
23  )
24
25  return {
26    value,
27    update,
28  }
29}
30
31// SOLUTION:
32// function useStorage <T extends object>(name: string, initialValue: T): {
33//   value: T,
34//   update(val: T): void
35// } {
36//   const [value, setValue] = useState<T>(initialValue)
37
38//   useEffect(() => {
39//     const t = setTimeout(() => {
40//       const val = JSON.parse(localStorage.getItem(name) || '{}')
41//       if (value !== val) {
42//         setValue(val)
43//       }
44//     }, 500)
45//     return () => clearTimeout(t)
46//   })
47
48//   const update = useCallback(
49//     (val) => {
50//       localStorage.setItem(name, JSON.stringify(val || '{}'))
51//       setValue(val)
52//     },
53//     [name, setValue]
54//   )
55
56//   return {
57//     value,
58//     update,
59//   }
60// }
61
62
63
64////////////////////////////////////////
65// 2. Type the following function looking at its body and usage:
66
67function reduce(arr, iterator, initialValue = undefined) {
68  let acc = initialValue
69  for (let index = 0; index < arr.length; index++) {
70    acc = iterator(acc, arr[index])
71  }
72  return acc
73}
74
75// Usage:
76
77reduce([1, 2, 3, 4], (sum, value) => sum + value, 0)
78
79reduce(
80  [1, 2, 3, 4],
81  (acc, value) => {
82    acc.total += value
83    return acc
84  },
85  { total: 0 }
86)
87
88reduce([1, 2, 3, 4], (acc, value) => {
89  if (!acc) {
90    acc = { result: value }
91  } else {
92    acc.result = value - acc.result
93  }
94  return acc
95})
96
97// SOLUTION:
98// function reduce<T, A = undefined>(arr: T[], iterator: (acc: A, val: T) => A, initialValue?: A) {
99//   let acc = initialValue
100//   for (let index = 0; index < arr.length; index++) {
101//     acc = iterator(acc, arr[index])
102//   }
103//   return acc
104// }
105
106// // Usage:
107
108// reduce([1, 2, 3, 4], (sum, value) => sum + value, 0)
109
110// reduce([1, 2, 3, 4], (acc, value) => {
111//   acc.total += value
112//   return acc
113// }, { total: 0 })
114
115// reduce<number, { result: number }>([1, 2, 3, 4], (acc, value) => {
116//   if (!acc) {
117//     acc = { result: value }
118//   } else {
119//     acc.result = value - acc.result
120//   }
121//   return acc
122// })
123
124////////////////////////////////////////
125// 3. Provide the proper typings for the following function:
126
127function compose(fn1, fn2) {
128  return (initialArg) => fn1(fn2(initialArg))
129}
130
131const a = compose(
132  (num) => num.toString(),
133  (initialNumber: number) => initialNumber + 2
134)
135// a is expected to be of type `(a: number) => string`
136
137// SOLUTION:
138// function compose<R3, R2, R1>(fn1: (arg: R3) => R2, fn2: (arg: R1) => R3): (initialArg: R1) => R2 {
139//   return (initialArg: R1) => fn1(fn2(initialArg))
140// }
141
142// const a = compose((a) => a.toString(), (a: number) => a + 2)
143
144
We use cookies to collect statistics through Google Analytics.
Do not track
 
Allow cookies