Total TypeScript - Beginner === ![](https://i.imgur.com/Ohu1K6L.png) --- ###### tags: `TypeScript` > The course was made by Matt Popcock, you can refer to this [repo](https://github.com/total-typescript/beginners-typescript-tutorial) to clone it or open [GitPod](https://gitpod.io/#https://github.com/total-typescript/beginners-typescript) > Once you downloaded it, go into the folder and run `npm install` to install dependencies, if you use GitPod, just run `npm install`. ### 1. The Implicit ‘Any’ Type Error Visit `src` folder and you will see `[topic]-problem.ts`, here we are at exercise 01, it is a function which is used for adding numbers, run `npm run exercise 01` to run the test. #### Exercies 01 ![](https://i.imgur.com/8wWnH2u.png) #### Test result The functionality is okay. ![](https://i.imgur.com/FnKDDbb.png) #### Checking type Looks like it's faied when it comes to check types for parameters `a` and `b`. ![](https://i.imgur.com/bl0pml9.png) --- #### Solution Let's take a look at the error, it said `Parameter a / b has an any type`. What it can't be `any` type? First of all, what is `any`, and in which situation we can use `any` as an type? - We can use whenever we don’t want a particular value to cause typechecking errors, but why it caused error in exercise 01? - The function is meant to add numbers, so if type of `a` or `b` has `any` type, even if the functionality was passed, TS expected us to specify the types for `a` and `b`, and **we should always be specific for argument of types**. - Since the functionality was to add `numbers`, thereofore we should specify both `a` and `b` as type `number`. #### Amendment ![](https://i.imgur.com/zINjepe.png) #### Test result ![](https://i.imgur.com/8dSc2uU.png) --- > References: > [TS Handbook - any](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html?#any) > [TS Don't and Do's for any](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#any) > Reminder: > ❌ Don’t use `any` as a type unless you are in the process of migrating a JavaScript project to TypeScript. --- ### 2. Working With Object Params #### Exercise 02 ![](https://i.imgur.com/JtaExgh.png) Here we have the same function `addTwoNumbers`, but this is time, it needs to accept an `object`, #### Checking type ![](https://i.imgur.com/YqUaC7B.png) It showed just like the exercise 01, `params` implicitly has an `any` type, as we can see the code above, it needs to accept an `object`, let's fix type of `params` from an `any` type to `object`. We can define type of `object` in three ways. ##### Solution - 1 : Define types inline directly(anonymously) ![](https://i.imgur.com/ng3BLJz.png) ##### Solution - 2 : Use `Type alias` ![](https://i.imgur.com/i9UYiBn.png) #### Solution - 3 : Use `interface` ![](https://i.imgur.com/dEOKMRV.png) Let's breakdown for `Type alias` and `interface`. - When we want to use the same type more than once and refer to it by a single name, `type alias` and `interface` come in handy. - Almost all features of an `interface` are available in `type alias`. - Key distinction is that a type **cannot be re-opened to add new properties** vs an **interface which is always extendable**. ```typescript! // Valid if using interface interface Dog { name: string; } interface Dog { age: number; } // Invalid if using type alias type Dog = { name:string; } type Dog = { age:number; } ``` --- > Reference: > [TS Handbook - Object](https://www.typescriptlang.org/docs/handbook/2/objects.html#handbook-content) --- ### 3. Set Properties as Optional #### Exercise 03 ![](https://i.imgur.com/bJQSsbd.png) #### Test result ![](https://i.imgur.com/ZtghZj8.png) Here let's make the `last` as **optional**. If we want a value to be shown optional, we can add `?` in front of `:`, for example: `const name?: string;`, it's acutally says `const name = string | undefined;` #### Solution - 1 : Use optional parameter ![](https://i.imgur.com/k1yr5Ja.png) #### Solution - 2 : undefined ![](https://i.imgur.com/UXI1HLm.png) With solution 2, we still need to assign `undefined` to param `last`, so it would be easier to use optional parameter. --- > Reference: > [TS Handbook - optional parameter](https://www.typescriptlang.org/docs/handbook/2/functions.html#optional-parameters) > [TS Don't and Do's for optional parameter](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#callback-types) --- ### 4. Optional Parameters #### Exercise 04 ![](https://i.imgur.com/C4hfMnr.png) Like the exercise 03, this time we need to find the way to make `last` optional. #### Checking type ![](https://i.imgur.com/cKTakiH.png) #### Solution - 1 : Use optional parameter ![](https://i.imgur.com/PSWHAyZ.png) #### Solution - 2 : Define directly and assign `undefined` as second argument ![](https://i.imgur.com/TzgKtfB.png) With solution 2, we still need to assign `undefined` to param `last`, so it would be easier to use optional parameter. --- > Reference: > [TS Handbook - optional parameter](https://www.typescriptlang.org/docs/handbook/2/functions.html#optional-parameters) > [TS Don't and Do's for optional parameter](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#callback-types) --- ### 5. Assign Type to a Variable #### Exercise 05 ![](https://i.imgur.com/KyWtfVr.png) #### Checking type ![](https://i.imgur.com/sOVhzRI.png) The error message: `Argument of type '{}' is not assignable to parameter of type 'User'. Type '{}' is missing the following properties from type 'User': id, firstName, lastName, isAdmin` #### Solution ![](https://i.imgur.com/NRX2TbV.png) With solution, if we don't specify `const defualtUser: User = {...}`, there won't be any errores. but if we miss or misspell a property, the error will show down below like the image below, and this is not what we want, a better way is to let TS show error at the variable so that we can clarify the issue. #### Misspell `isAdmin` without specifying type for variable defaultUSer Error msg: Not clarify the issue enough. `Argument of type '{ id: number; firstName: string; lastName: string; isadmin: boolean; }' is not assignable to parameter of type 'User'. Property 'isAdmin' is missing in type '{ id: number; firstName: string; lastName: string; isadmin: boolean; }' but required in type 'User'` ![](https://i.imgur.com/rjqyLeU.png) #### Misspell `isAdmin` with specifying type for variable defaultUSer Error msg: Clarify the issue plaintly. `Type '{ id: number; firstName: string; lastName: string; isadmin: boolean; }' is not assignable to type 'User'. Object literal may only specify known properties, but 'isadmin' does not exist in type 'User'. Did you mean to write 'isAdmin'?` ![](https://i.imgur.com/uT0Xn4P.png) --- > Reference: > [TS Handbook - Defining types](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html#defining-types) --- ### 6. Constraining Value Type #### Exercise 06 ![](https://i.imgur.com/GjHWXtF.png) In this exercise, we want to make our `role` to be either `admin`, `user` or `super-admin`. #### Solution - 1 : Use Union type ![](https://i.imgur.com/ClnctQN.png) We use `|` to separate different values, just like we specify an `union type`, for example: `const age = string | number`. #### Solution - 2 : Use type alias In this case, we can also use `Type alias` to define `role's` value and assign to it. In this case, `interface` is not sutiable due to we can't assign value to an `interface`. ![](https://i.imgur.com/9PCDyqL.png) --- > Reference: > [TS Handbook - Union type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) > [TS Don't & Do's - Union type](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#use-union-types) > [TS 新手指南](https://willh.gitbook.io/typescript-tutorial/basics/union-types) --- ### 7. Working With Array #### Exercise 07 ![](https://i.imgur.com/wz9MwTk.png) The error msg: `Type '{ id: number; title: string; }[]' is missing the following properties from type 'Post': id, title`. The issue occurres because of `posts` is an `array`, but in our `User` interface, it the type of `posts` is not correct, it has to be an `array`. Both solutions can resolve the issue. #### Solution: ![](https://i.imgur.com/Gop8F6y.png) #### Use `Generic` (Advanced topic) ![](https://i.imgur.com/mFIQPDp.png) We can specify array of only contains specifc value, for example: `string[]` means the array should only contains `string`; `number[]` should only contains `number`. --- > Reference: > [TS Handbook-array](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#arrays) > [TS - Generic](https://www.typescriptlang.org/docs/handbook/2/generics.html#handbook-content) --- ### 8. Function Return Type Annotation #### Exercise 08 ![](https://i.imgur.com/7HWiSWy.png) #### Checking type ![](https://i.imgur.com/orHMLkf.png) #### Solution ![](https://i.imgur.com/Y5YAVNO.png) We assign type `User` after brakets, and inside the `return`, we provide values that are required by type `User`, now if we misspell or miss one property, the error will occur within the scope and clarify the issue. Error msg: `Type '{ id: number; firstName: string; lastName: string; role: "admin"; post: { id: number; title: string; }[]; }' is not assignable to type 'User'. Object literal may only specify known properties, but 'post' does not exist in type 'User'. Did you mean to write 'posts'?` ![](https://i.imgur.com/XlLXQTh.png) --- ### 9. Typing Promises and Async Requests #### Exercise 9 ![](https://i.imgur.com/3qZleLA.png) #### Checking type ![](https://i.imgur.com/LGdfLXA.png) #### Solution 1: Promise<> Hover over to the error message, TS will recommand we to use `Promise<LukeSkywalker>` below to fix the error. ``` interface LukeSkywalker The return type of an async function or method must be the global Promise<T> type. Did you mean to write `Promise<LukeSkywalker>?ts(1064) ``` ![](https://i.imgur.com/DyyRLUk.png) #### Solution 2: Assign type to data Assign type to data that we are going to fetch directly. ![](https://i.imgur.com/2CHNkVW.png) #### Solution 3: Cast Data as a Type - [Type Casting](https://www.typescripttutorial.net/typescript-tutorial/type-casting/) - In TypeScript, you can use the `as` keyword or `<>` operator for type castings. ![](https://i.imgur.com/My5Rn3e.png) --- ### 10. Passing Type Arguments #### Exercise 10 ![](https://i.imgur.com/sccYE8d.png) #### Checking type ![](https://i.imgur.com/aaWDBIt.png) #### Solution - [TyppScript Set](https://howtodoinjava.com/typescript/sets/) - Use `new` keyword to create a `Set` ```typescript= // Create a new Set const total = new Set(); // Example 1: Add type number // Can only accept value of number const total = new Set<number>(); // Example 2: Add type string // Can only accept value of string const direction = new Set<string>(["East", "West", "South", "North"]); ``` ```typescript= // If we pass wrong type of value, TS will show error const total = new Set<number>(); total.add("Hello world"); ``` ![](https://i.imgur.com/ENscN28.png) - Methods of `Set` - `set.add(v)` – adds values into the Set. - `set.has(v)` – checks the existence of a value in the Set. - `set.delete(v)` – deletes a value from the Set. - `set.clear()` – clear all values from the Set. - `set.size` – ‘size‘ property will return size of Set. Let's take a look at the code below. ```typescript= const guitarists = new Set(); guitarists.add("Jimi Hendrix"); guitarists.add("Eric Clapton"); ``` It takes values of `string`, therefore we should add type of `string` for it. ![](https://i.imgur.com/K1ilHFt.png) --- ### 11. Assigning Dynamic Keys to an Object #### Exercise 11 ![](https://i.imgur.com/6GpvIZw.png) #### Checking type ![](https://i.imgur.com/2eFjlyF.png) #### Solution 1: Using `Record<Keys, Type>` >Whenever you see index in a type error, it's usually referring to the key of an object. - [Utility Types: Record<Keys, Type>](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) ![](https://i.imgur.com/5LJB4yM.png) #### Solution 2: Assign type directly ![](https://i.imgur.com/ou8SByP.png) #### Solution 3: Using interface || type ![](https://i.imgur.com/jpdyvtU.png) If we did not pass the correct type, TS will show error. ```typescript= // interface ICahce { // [id: string]: string; // } type TCahce = { [id: string]: string; } const createCache = () => { const cache: TCahce = {}; // const cache: Record<string, string> = {} // const cache: { // [id: string]: string // } = {}; const add = (id: string, value: string) => { cache[id] = value; } return {add}; } const cache = createCache(); // Change string to a number cache.add(2, "Matt"); ``` ![](https://i.imgur.com/fuUN9NV.png) --- ### 12. Narrowing Down Union Types #### Exercise 12 ![](https://i.imgur.com/zQ9ZXzn.png) #### Checking type ![](https://i.imgur.com/ApNRblV.png) #### Solution : Using `typeof` to narrow down - [typeof type operator](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html#the-typeof-type-operator) ![](https://i.imgur.com/ic1GUKa.png) --- ### 13. Typing Errors in a Try-Catch #### Exercise 13 ![](https://i.imgur.com/3Ha0Iwe.png) #### Checking type ![](https://i.imgur.com/lun62Mw.png) #### Solution 1: Using `any`(Not recommended) If we use `any` as a type of `e`, it will fix the error, but this has several downsides, one is that it won't check if there's a typo or it won't autocomplete on it. ![](https://i.imgur.com/UuuPuK5.png) With a typo, there's no error. ![](https://i.imgur.com/Pwj61RV.png) #### Solution 2: Using data casting `as` If we use `as` here, it won't show error as well, but it has some downsides too. ![](https://i.imgur.com/hbe49WY.png) In real world, it contains many codes inside of a try-catch block, what if someone forgot to add `Error`,which means `e` might not be an `Error`, here `e` is `undefined`, but TS won't show any error to us until we execute some testing. ![](https://i.imgur.com/o0ppGS0.png) #### Solution 3: Using `instanceof` - [Narrowing - instanceof](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#instanceof-narrowing) ![](https://i.imgur.com/DEAdgNR.png) --- ### 14. Inheriting Interface Properties #### Exercise 14 ![](https://i.imgur.com/cDhBjEr.png) #### Solution: Using `extends` - [Extending types](https://www.typescriptlang.org/docs/handbook/2/objects.html#extending-types) We can pull out same property and create another `interface` as a base, and let other interface to extend it. Since those `interfaces` have same property - `id`, we can something like this. ![](https://i.imgur.com/EeiWyc6.png) **Note: Can't use `type` to inheriting types, `extends` can be used for interfaces and classes only.** Using `type` ![](https://i.imgur.com/BO1vcnp.png) Using `interface` ![](https://i.imgur.com/PcH6wPj.png) --- ### 15. Combining Types to Create New Types #### Exercise 15 ![](https://i.imgur.com/hAHQIcA.png) #### Checking type ![](https://i.imgur.com/MfYclCi.png) #### Solution: Using `&` as intersaction types - [Intersaction Types](https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types) We can use `&` to define a new type that represents both `User` and `Post`, one thing that needs to be cautious is that `posts` is an object array. ![](https://i.imgur.com/PNxKwOT.png) Or we can define directly. ![](https://i.imgur.com/lzZ3HUZ.png) --- ### Selectively construct Types from other Types #### Exercise 16 ![](https://i.imgur.com/KqZQ1Ex.png) #### Checking type ![](https://i.imgur.com/AGDrmDO.png) #### Solution 1: Using `omit<Type, keys>` Constructs a type by picking all properties from Type and then **removing** Keys (string literal or union of string literals). Code below shows that includes all properites from type `User`, except `id`. ![](https://i.imgur.com/f0b5Ze5.png) > Reference > [TS docs - Omit](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) #### Solution 2: Using `Pick<Type, keys>` Constructs a type by picking the set of properties Keys (string literal or union of string literals) from Type. Code below shows that we only want `firstName` and `lastname` from type `User` ![](https://i.imgur.com/EOIavqY.png) > Reference > [Utility Types](https://www.typescriptlang.org/docs/handbook/utility-types.html) --- ### Function Types #### Exercise 17 ![](https://i.imgur.com/qmuX2Vg.png) #### Solutoin 1: Declare type directly. ![](https://i.imgur.com/BoXcM6f.png) #### Solution 2: Declare a type outside ![](https://i.imgur.com/CL1g6ER.png) --- ### Typing Async Functions #### Exercise 18 ![](https://i.imgur.com/uwc7vCt.png)