diff --git a/README.md b/README.md index d467582e..c824922d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,5 @@ beginner typescript tutorial -## Quickstart - -Take the course on [Total TypeScript](https://totaltypescript.com/tutorials/beginners-typescript). There, you'll find: - -- Video explanations for each problem and solution -- Transcripts -- Text explanations -- A built-in Stackblitz editor - ## Installation Instructions Clone this repo or [open in Gitpod](https://gitpod.io/#https://github.com/total-typescript/beginners-typescript). @@ -24,43 +15,9 @@ npm run exercise 01 npm run solution 01 ``` -## How to take the course - -You'll notice that the course is split into exercises. Each exercise is split into a `*.problem.ts` and a `*.solution.ts`. - -To take an exercise: - -1. Go into `*.problem.ts` -2. Run `npm run exercise 01`, where `01` is the number of the exercise you're on. - -The `exercise` script will run TypeScript typechecks and a test suite on the exercise. - -This course encourages **active, exploratory learning**. In the video, I'll explain a problem, and **you'll be asked to try to find a solution**. To attempt a solution, you'll need to: - -1. Check out [TypeScript's docs](https://www.typescriptlang.org/docs/handbook/intro.html) -2. Try to find something that looks relevant. -3. Give it a go to see if it solves the problem. - -You'll know if you've succeeded because the tests will pass. - -**If you succeed**, or **if you get stuck**, unpause the video and check out the `*.solution.ts`. You can see if your solution is better or worse than mine! - -You can run `npm run solution 01` to run the tests and typechecking on the solution. - -## Acknowledgements - -Say thanks to Matt on [Twitter](https://twitter.com/mattpocockuk) or by joining his [Discord](https://discord.gg/8S5ujhfTB3). Consider signing up to his [Total TypeScript course](https://totaltypescript.com). - -## Reference - -### `npm run exercise 01` - -Alias: `npm run e 01` - -Run the corresponding `*.problem.ts` file. +## Description -### `npm run solution 01` +This is fork form `total-typescript/beginners-typescript-tutorial` in order to comprehend some of the best practices or common mistakes using TypeScript. -Alias: `npm run s 01` +It stands as a support for me while working. Each `*.problem.ts` has a link to the official TypeScript documentation for a full explanation of the issue or for the data type that is using there. -Run the corresponding `*.solution.ts` file. If there are multiple, it runs only the first one. diff --git a/package.json b/package.json index 69c71bc4..44da7aa8 100644 --- a/package.json +++ b/package.json @@ -61,4 +61,4 @@ "express": "^4.18.1", "zod": "^3.17.10" } -} +} \ No newline at end of file diff --git a/src/01-number.problem.ts b/src/01-number.problem.ts index 0f6286e0..31fe3791 100644 --- a/src/01-number.problem.ts +++ b/src/01-number.problem.ts @@ -8,3 +8,5 @@ it("Should add the two numbers together", () => { expect(addTwoNumbers(2, 4)).toEqual(6); expect(addTwoNumbers(10, 10)).toEqual(20); }); + +// https://www.typescriptlang.org/docs/handbook/2/functions.html#function-type-expressions \ No newline at end of file diff --git a/src/01-number.solution.ts b/src/01-number.solution.ts index 5f21a88e..9cf5e89c 100644 --- a/src/01-number.solution.ts +++ b/src/01-number.solution.ts @@ -7,4 +7,4 @@ export const addTwoNumbers = (a: number, b: number) => { it("Should add the two numbers together", () => { expect(addTwoNumbers(2, 4)).toEqual(6); expect(addTwoNumbers(10, 10)).toEqual(20); -}); +}); \ No newline at end of file diff --git a/src/02-object-param.problem.ts b/src/02-object-param.problem.ts index 8c331765..5e90e861 100644 --- a/src/02-object-param.problem.ts +++ b/src/02-object-param.problem.ts @@ -19,3 +19,5 @@ it("Should add the two numbers together", () => { }), ).toEqual(30); }); + +// https://www.typescriptlang.org/docs/handbook/2/objects.html diff --git a/src/02-object-param.solution.1.ts b/src/02-object-param.solution.1.ts index 4b7248ce..b4c706cb 100644 --- a/src/02-object-param.solution.1.ts +++ b/src/02-object-param.solution.1.ts @@ -1,6 +1,11 @@ import { expect, it } from "vitest"; -export const addTwoNumbers = (params: { first: number; second: number }) => { +type AddNumbers = { + first: number + second: number, +} + +export const addTwoNumbers = (params: AddNumbers) => { return params.first + params.second; }; diff --git a/src/02-object-param.solution.2.ts b/src/02-object-param.solution.2.ts deleted file mode 100644 index a3a57292..00000000 --- a/src/02-object-param.solution.2.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect, it } from "vitest"; - -type AddTwoNumbersArgs = { - first: number; - second: number; -}; - -export const addTwoNumbers = (params: AddTwoNumbersArgs) => { - return params.first + params.second; -}; - -it("Should add the two numbers together", () => { - expect( - addTwoNumbers({ - first: 2, - second: 4, - }), - ).toEqual(6); - - expect( - addTwoNumbers({ - first: 10, - second: 20, - }), - ).toEqual(30); -}); diff --git a/src/02-object-param.solution.3.ts b/src/02-object-param.solution.3.ts deleted file mode 100644 index 72959b23..00000000 --- a/src/02-object-param.solution.3.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect, it } from "vitest"; - -interface AddTwoNumbersArgs { - first: number; - second: number; -} - -export const addTwoNumbers = (params: AddTwoNumbersArgs) => { - return params.first + params.second; -}; - -it("Should add the two numbers together", () => { - expect( - addTwoNumbers({ - first: 2, - second: 4, - }), - ).toEqual(6); - - expect( - addTwoNumbers({ - first: 10, - second: 20, - }), - ).toEqual(30); -}); diff --git a/src/03-optional-properties.problem.ts b/src/03-optional-properties.problem.ts index 9ee58fcb..c4236722 100644 --- a/src/03-optional-properties.problem.ts +++ b/src/03-optional-properties.problem.ts @@ -23,3 +23,5 @@ it("Should work with the first and last name", () => { expect(name).toEqual("Matt Pocock"); }); + +// https://www.typescriptlang.org/docs/handbook/2/objects.html#optional-properties \ No newline at end of file diff --git a/src/04-optional-params.problem.ts b/src/04-optional-params.problem.ts index 023bb997..4b4ac6b4 100644 --- a/src/04-optional-params.problem.ts +++ b/src/04-optional-params.problem.ts @@ -18,3 +18,5 @@ it("Should work with the first and last name", () => { expect(name).toEqual("Matt Pocock"); }); + +// https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#use-optional-parameters \ No newline at end of file diff --git a/src/05-assigning-types-to-variables.problem.ts b/src/05-assigning-types-to-variables.problem.ts index 50de8989..4a81c27e 100644 --- a/src/05-assigning-types-to-variables.problem.ts +++ b/src/05-assigning-types-to-variables.problem.ts @@ -20,3 +20,5 @@ const getUserId = (user: User) => { it("Should get the user id", () => { expect(getUserId(defaultUser)).toEqual(1); }); + +// \ No newline at end of file diff --git a/src/05-assigning-types-to-variables.solution.ts b/src/05-assigning-types-to-variables.solution.ts index 174c0fc0..71e71728 100644 --- a/src/05-assigning-types-to-variables.solution.ts +++ b/src/05-assigning-types-to-variables.solution.ts @@ -13,9 +13,9 @@ interface User { */ const defaultUser: User = { id: 1, - firstName: "Matt", - lastName: "Pocock", - isAdmin: true, + firstName: "Robert", + lastName: "Stoia", + isAdmin: true }; const getUserId = (user: User) => { diff --git a/src/06-unions.problem.ts b/src/06-unions.problem.ts index 55420fd0..116b3488 100644 --- a/src/06-unions.problem.ts +++ b/src/06-unions.problem.ts @@ -18,3 +18,5 @@ export const defaultUser: User = { // @ts-expect-error role: "I_SHOULD_NOT_BE_ALLOWED", }; + +// https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#unions \ No newline at end of file diff --git a/src/06-unions.solution.ts b/src/06-unions.solution.ts index c441e656..923021c2 100644 --- a/src/06-unions.solution.ts +++ b/src/06-unions.solution.ts @@ -2,12 +2,6 @@ interface User { id: number; firstName: string; lastName: string; - /** - * How do we ensure that role is only one of: - * - 'admin' - * - 'user' - * - 'super-admin' - */ role: "admin" | "user" | "super-admin"; } diff --git a/src/07-arrays.solution.2.ts b/src/07-arrays.solution.2.ts deleted file mode 100644 index ea725b0f..00000000 --- a/src/07-arrays.solution.2.ts +++ /dev/null @@ -1,29 +0,0 @@ -interface User { - id: number; - firstName: string; - lastName: string; - role: "admin" | "user" | "super-admin"; - posts: Array; -} - -interface Post { - id: number; - title: string; -} - -export const defaultUser: User = { - id: 1, - firstName: "Matt", - lastName: "Pocock", - role: "admin", - posts: [ - { - id: 1, - title: "How I eat so much cheese", - }, - { - id: 2, - title: "Why I don't eat more vegetables", - }, - ], -}; diff --git a/src/08-function-return-type-annotations.problem.ts b/src/08-function-return-type-annotations.problem.ts index af1e7217..7752e98a 100644 --- a/src/08-function-return-type-annotations.problem.ts +++ b/src/08-function-return-type-annotations.problem.ts @@ -32,3 +32,5 @@ it("Should return a valid user", () => { expect(user.posts[0].id).toBeTypeOf("number"); expect(user.posts[0].title).toBeTypeOf("string"); }); + +// https://www.typescriptlang.org/docs/handbook/2/functions.html diff --git a/src/08-function-return-type-annotations.solution.ts b/src/08-function-return-type-annotations.solution.ts index c0aa1d2e..c33a9cc6 100644 --- a/src/08-function-return-type-annotations.solution.ts +++ b/src/08-function-return-type-annotations.solution.ts @@ -20,13 +20,13 @@ interface Post { const makeUser = (): User => { return { id: 1, - firstName: "Matt", - lastName: "Pocock", - role: "admin", + firstName: "Robert", + lastName: "Stoia", + role: "super-admin", posts: [ { id: 1, - title: "How I eat so much cheese", + title: "First Post", }, ], }; diff --git a/src/09-promises.problem.ts b/src/09-promises.problem.ts index 09be97fc..9f65fe54 100644 --- a/src/09-promises.problem.ts +++ b/src/09-promises.problem.ts @@ -16,3 +16,5 @@ export const fetchLukeSkywalker = async (): LukeSkywalker => { return data; }; + +// diff --git a/src/09-promises.solution.2.ts b/src/09-promises.solution.2.ts deleted file mode 100644 index c022e2ef..00000000 --- a/src/09-promises.solution.2.ts +++ /dev/null @@ -1,18 +0,0 @@ -interface LukeSkywalker { - name: string; - height: string; - mass: string; - hair_color: string; - skin_color: string; - eye_color: string; - birth_year: string; - gender: string; -} - -export const fetchLukeSkywalker = async () => { - const data = await fetch("https://swapi.dev/api/people/1").then((res) => { - return res.json(); - }); - - return data as LukeSkywalker; -}; diff --git a/src/09-promises.solution.3.ts b/src/09-promises.solution.3.ts deleted file mode 100644 index b3a758a6..00000000 --- a/src/09-promises.solution.3.ts +++ /dev/null @@ -1,20 +0,0 @@ -interface LukeSkywalker { - name: string; - height: string; - mass: string; - hair_color: string; - skin_color: string; - eye_color: string; - birth_year: string; - gender: string; -} - -export const fetchLukeSkywalker = async () => { - const data: LukeSkywalker = await fetch( - "https://swapi.dev/api/people/1" - ).then((res) => { - return res.json(); - }); - - return data; -}; diff --git a/src/11-record.problem.ts b/src/11-record.problem.ts index 1cc74453..412aae45 100644 --- a/src/11-record.problem.ts +++ b/src/11-record.problem.ts @@ -34,3 +34,5 @@ it("Should remove values from the cache", () => { expect(cache.cache["123"]).toEqual(undefined); }); + +// https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type \ No newline at end of file diff --git a/src/11-record.solution.2.ts b/src/11-record.solution.2.ts deleted file mode 100644 index caa20c32..00000000 --- a/src/11-record.solution.2.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { expect, it } from "vitest"; - -const createCache = () => { - const cache: { - [id: string]: string; - } = {}; - - const add = (id: string, value: string) => { - cache[id] = value; - }; - - const remove = (id: string) => { - delete cache[id]; - }; - - return { - cache, - add, - remove, - }; -}; - -it("Should add values to the cache", () => { - const cache = createCache(); - - cache.add("123", "Matt"); - - expect(cache.cache["123"]).toEqual("Matt"); -}); - -it("Should remove values from the cache", () => { - const cache = createCache(); - - cache.add("123", "Matt"); - cache.remove("123"); - - expect(cache.cache["123"]).toEqual(undefined); -}); diff --git a/src/11-record.solution.3.ts b/src/11-record.solution.3.ts deleted file mode 100644 index e21082c7..00000000 --- a/src/11-record.solution.3.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { expect, it } from "vitest"; - -interface Cache { - [id: string]: string; -} - -const createCache = () => { - const cache: Cache = {}; - - const add = (id: string, value: string) => { - cache[id] = value; - }; - - const remove = (id: string) => { - delete cache[id]; - }; - - return { - cache, - add, - remove, - }; -}; - -it("Should add values to the cache", () => { - const cache = createCache(); - - cache.add("123", "Matt"); - - expect(cache.cache["123"]).toEqual("Matt"); -}); - -it("Should remove values from the cache", () => { - const cache = createCache(); - - cache.add("123", "Matt"); - cache.remove("123"); - - expect(cache.cache["123"]).toEqual(undefined); -}); diff --git a/src/12-typeof-narrowing.problem.ts b/src/12-typeof-narrowing.problem.ts index 7811011a..2aaaf77e 100644 --- a/src/12-typeof-narrowing.problem.ts +++ b/src/12-typeof-narrowing.problem.ts @@ -9,3 +9,5 @@ it("Should return the amount when passed an object", () => { it("Should return the amount when passed a number", () => { expect(coerceAmount(20)).toEqual(20); }); + +// https://www.typescriptlang.org/docs/handbook/2/narrowing.html#handbook-content \ No newline at end of file diff --git a/src/13-catch-blocks.solution.2.ts b/src/13-catch-blocks.solution.2.ts deleted file mode 100644 index c3ca74d5..00000000 --- a/src/13-catch-blocks.solution.2.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { expect, it } from "vitest"; - -const tryCatchDemo = (state: "fail" | "succeed") => { - try { - if (state === "fail") { - throw new Error("Failure!"); - } - } catch (e) { - return (e as Error).message; - } -}; - -it("Should return the message when it fails", () => { - expect(tryCatchDemo("fail")).toEqual("Failure!"); -}); diff --git a/src/13-catch-blocks.solution.3.ts b/src/13-catch-blocks.solution.3.ts deleted file mode 100644 index c47d9362..00000000 --- a/src/13-catch-blocks.solution.3.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { expect, it } from "vitest"; - -const tryCatchDemo = (state: "fail" | "succeed") => { - try { - if (state === "fail") { - throw new Error("Failure!"); - } - } catch (e) { - if (e instanceof Error) { - return e.message; - } - } -}; - -it("Should return the message when it fails", () => { - expect(tryCatchDemo("fail")).toEqual("Failure!"); -}); diff --git a/src/14-extends.problem.ts b/src/14-extends.problem.ts index e4689052..3b8881a7 100644 --- a/src/14-extends.problem.ts +++ b/src/14-extends.problem.ts @@ -28,3 +28,5 @@ type tests = [ Expect>, Expect>, ]; + +// https://www.typescriptlang.org/docs/handbook/2/objects.html#extending-types \ No newline at end of file diff --git a/src/15-intersection.problem.ts b/src/15-intersection.problem.ts index a6e5bc7d..9e65bc0a 100644 --- a/src/15-intersection.problem.ts +++ b/src/15-intersection.problem.ts @@ -14,7 +14,7 @@ interface Post { * How do we type this return statement so it's both * User AND { posts: Post[] } */ -export const getDefaultUserAndPosts = (): unknown => { +export const getDefaultUserAndPosts = () => { return { id: "1", firstName: "Matt", @@ -32,3 +32,5 @@ export const getDefaultUserAndPosts = (): unknown => { const userAndPosts = getDefaultUserAndPosts(); console.log(userAndPosts.posts[0]); + +// https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types \ No newline at end of file diff --git a/src/16-omit-and-pick.problem.ts b/src/16-omit-and-pick.problem.ts index 8d75c8b9..044541dc 100644 --- a/src/16-omit-and-pick.problem.ts +++ b/src/16-omit-and-pick.problem.ts @@ -14,3 +14,5 @@ interface User { type MyType = unknown; type tests = [Expect>]; + +// https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys \ No newline at end of file diff --git a/src/16-omit-and-pick.solution.2.ts b/src/16-omit-and-pick.solution.2.ts deleted file mode 100644 index 99e18ffe..00000000 --- a/src/16-omit-and-pick.solution.2.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Equal, Expect } from "./helpers/type-utils"; - -interface User { - id: string; - firstName: string; - lastName: string; -} - -/** - * How do we create a new object type with _only_ the - * firstName and lastName properties of User? - */ - -type MyType = Pick; - -type tests = [Expect>]; diff --git a/src/16-omit-and-pick.solution.1.ts b/src/16-omit-and-pick.solution.ts similarity index 100% rename from src/16-omit-and-pick.solution.1.ts rename to src/16-omit-and-pick.solution.ts diff --git a/src/17-function-types.problem.ts b/src/17-function-types.problem.ts index a228d9e7..6774ef3b 100644 --- a/src/17-function-types.problem.ts +++ b/src/17-function-types.problem.ts @@ -3,7 +3,7 @@ import { Equal, Expect } from "./helpers/type-utils"; /** * How do we type onFocusChange? */ -const addListener = (onFocusChange: unknown) => { +const addListener = (onFocusChange: (isFocused: boolean) => void) => { window.addEventListener("focus", () => { onFocusChange(true); }); @@ -18,3 +18,5 @@ addListener((isFocused) => { type tests = [Expect>]; }); + +// https://www.typescriptlang.org/docs/handbook/2/functions.html#function-type-expressions \ No newline at end of file diff --git a/src/17-function-types.solution.2.ts b/src/17-function-types.solution.2.ts deleted file mode 100644 index 01325591..00000000 --- a/src/17-function-types.solution.2.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Equal, Expect } from "./helpers/type-utils"; - -/** - * How do we type onFocusChange? - */ -type FocusListener = (isFocused: boolean) => void; - -const addListener = (onFocusChange: FocusListener) => { - window.addEventListener("focus", () => { - onFocusChange(true); - }); - - window.addEventListener("blur", () => { - onFocusChange(false); - }); -}; - -addListener((isFocused) => { - console.log({ isFocused }); - - type tests = [Expect>]; -}); diff --git a/src/17-function-types.solution.1.ts b/src/17-function-types.solution.ts similarity index 100% rename from src/17-function-types.solution.1.ts rename to src/17-function-types.solution.ts