├── .gitignore ├── README.md ├── lesson01 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson02 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson03 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson04 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson05 ├── build │ ├── index.html │ └── js │ │ ├── copyright.js │ │ └── main.js ├── src │ ├── copyright.ts │ └── main.ts └── tsconfig.json ├── lesson06 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson07 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson08 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson09 ├── build │ ├── index.html │ └── js │ │ └── main.js ├── src │ └── main.ts └── tsconfig.json ├── lesson11 ├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── css │ │ └── style.css │ ├── main.ts │ ├── model │ │ ├── FullList.ts │ │ └── ListItem.ts │ ├── templates │ │ └── ListTemplate.ts │ └── vite-env.d.ts └── tsconfig.json ├── lesson12 ├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── components │ │ ├── Counter.tsx │ │ ├── Heading.tsx │ │ ├── List.tsx │ │ └── Section.tsx │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── lesson13 ├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── lesson14 ├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.tsx │ ├── Counter.tsx │ ├── assets │ │ └── react.svg │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── lesson15 ├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.tsx │ ├── Counter.tsx │ ├── assets │ │ └── react.svg │ ├── context │ │ └── CounterContext.tsx │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── lesson16 ├── .gitignore ├── data │ └── products.json ├── index.html ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── context │ │ ├── CartProvider.tsx │ │ └── ProductsProvider.tsx │ ├── images │ │ ├── item0001.jpg │ │ ├── item0002.jpg │ │ └── item0003.jpg │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts └── lesson17 ├── .gitignore ├── data └── products.json ├── index.html ├── package-lock.json ├── package.json ├── public └── vite.svg ├── src ├── App.tsx ├── assets │ └── react.svg ├── components │ ├── Cart.tsx │ ├── CartLineItem.tsx │ ├── Footer.tsx │ ├── Header.tsx │ ├── Nav.tsx │ ├── Product.tsx │ └── ProductList.tsx ├── context │ ├── CartProvider.tsx │ └── ProductsProvider.tsx ├── hooks │ ├── useCart.tsx │ └── useProducts.tsx ├── images │ ├── item0001.jpg │ ├── item0002.jpg │ └── item0003.jpg ├── index.css ├── main.tsx └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Typescript for Beginners 2 | 3 | ### Full Course - 17 Chapters 4 | 5 | --- 6 | 7 | ### Author Links 8 | 9 | 👋 Hello, I'm Dave Gray. 10 | 11 | ✅ [Check out my YouTube Channel with all of my tutorials](https://www.youtube.com/DaveGrayTeachesCode). 12 | 13 | 🚩 [Subscribe to my channel](https://bit.ly/3nGHmNn) 14 | 15 | ☕ [Buy Me A Coffee](https://buymeacoffee.com/DaveGray) 16 | 17 | 🚀 Follow Me: 18 | 19 | - [Twitter](https://twitter.com/yesdavidgray) 20 | - [LinkedIn](https://www.linkedin.com/in/davidagray/) 21 | - [Blog](https://yesdavidgray.com) 22 | - [Reddit](https://www.reddit.com/user/DaveOnEleven) 23 | 24 | --- 25 | 26 | ### Description 27 | 28 | 📺 [YouTube Playlist](https://www.youtube.com/playlist?list=PL0Zuz27SZ-6NS8GXt5nPrcYpust89zq_b) for this repository. 29 | 30 | 🚀 This repository shares ALL of the resources referenced during the Typescript for Beginners tutorial series. 31 | 32 | - 👉 Chapters 1-10 introduce TypeScript fundamentals. 33 | - 👉 Chapters 12-17 cover Typescript with React. 34 | 35 | ### 📚 Recommended Prerequisites 36 | - 🔗 [JavaScript for Beginners Course](https://youtu.be/EfAl9bwzVZk) 37 | - 🔗 [React for Beginners Course](https://youtu.be/RVFAyFWO4go) 38 | 39 | --- 40 | 41 | ### 🎓 Academic Honesty 42 | 43 | **DO NOT COPY FOR AN ASSIGNMENT** - Avoid plagiarism and adhere to the spirit of this [Academic Honesty Policy](https://www.freecodecamp.org/news/academic-honesty-policy/). 44 | 45 | --- 46 | 47 | ### ⚙ Free Web Dev Tools 48 | - 🔗 [Vite](https://vitejs.dev/) 49 | - 🔗 [Google Chrome Web Browser](https://google.com/chrome/) 50 | - 🔗 [Visual Studio Code (aka VS Code)](https://code.visualstudio.com/) 51 | - 🔗 [Live Server VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) 52 | 53 | ### 📚 References 54 | - 🔗 [Typescript Official Site](https://www.typescriptlang.org/) 55 | - 🔗 [Node.js & npm](https://nodejs.org/) 56 | - 🔗 [Anders Hejlsberg, Creator of Typescript and C# Interview](https://dev.to/destrodevshow/typescript-and-c-both-created-by-the-same-person-named-anders-hejlsberg-42g4) 57 | - 🔗 [Stackoverflow Survey Results](https://survey.stackoverflow.co/2022/#technology-most-popular-technologies) 58 | - - 🔗 [TypeScript + React Cheatsheet](https://github.com/typescript-cheatsheets/react) 59 | - 🔗 [React Official Site](https://reactjs.org/) 60 | 61 | ### 📚 Terminology 62 | - 🔗 [MDN - Static Typing](https://developer.mozilla.org/en-US/docs/Glossary/Static_typing) 63 | - 🔗 [MDN - Dynamic Typing](https://developer.mozilla.org/en-US/docs/Glossary/Dynamic_typing) 64 | - 🔗 [MDN - Type Coercion](https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion) 65 | - 🔗 [TypeScript - Type Assertions](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions) 66 | 67 | --- 68 | 69 | ### 💻 Source Code 70 | 71 | - 🔗 [Chapter 1 - Introduction, Setup & Config](https://github.com/gitdagray/typescript-course/tree/main/lesson01) 72 | - 🔗 [Chapter 2 - Basic Types](https://github.com/gitdagray/typescript-course/tree/main/lesson02) 73 | - 🔗 [Chapter 3 - Arrays, Tuples, Objects & Enums](https://github.com/gitdagray/typescript-course/tree/main/lesson03) 74 | - 🔗 [Chapter 4 - Type Aliases, Literals, Functions & Never Type](https://github.com/gitdagray/typescript-course/tree/main/lesson04) 75 | - 🔗 [Chapter 5 - Type Assertions & Type Casting](https://github.com/gitdagray/typescript-course/tree/main/lesson05) 76 | - 🔗 [Chapter 6 - Classes & Interfaces](https://github.com/gitdagray/typescript-course/tree/main/lesson06) 77 | - 🔗 [Chapter 7 - Index Signatures & keyof Assertions](https://github.com/gitdagray/typescript-course/tree/main/lesson07) 78 | - 🔗 [Chapter 8 - Generics](https://github.com/gitdagray/typescript-course/tree/main/lesson08) 79 | - 🔗 [Chapter 9 - Utility Types](https://github.com/gitdagray/typescript-course/tree/main/lesson09) 80 | - 🔗 Chapter 10 - Vite Introduction (_no source code_) 81 | - 🔗 [Chapter 11 - Beginners Project / Challenges](https://github.com/gitdagray/typescript-course/tree/main/lesson11) 82 | - 🔗 [Chapter 12 - React + Typescript Starter](https://github.com/gitdagray/typescript-course/tree/main/lesson12) 83 | - 🔗 [Chapter 13 - React Hooks + Typescript](https://github.com/gitdagray/typescript-course/tree/main/lesson13) 84 | - 🔗 [Chapter 14 - React useReducer + Typescript](https://github.com/gitdagray/typescript-course/tree/main/lesson14) 85 | - 🔗 [Chapter 15 - React useContext + Typescript](https://github.com/gitdagray/typescript-course/tree/main/lesson15) 86 | - 🔗 [Chapter 16 - React + Typescript Project - Part 1](https://github.com/gitdagray/typescript-course/tree/main/lesson16) 87 | -------------------------------------------------------------------------------- /lesson01/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson01/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | let username = 'Dave'; 3 | console.log(username); 4 | let a = 12; 5 | let b = '6'; 6 | let c = 2; 7 | console.log(a / b); 8 | console.log(c * b); 9 | -------------------------------------------------------------------------------- /lesson01/src/main.ts: -------------------------------------------------------------------------------- 1 | let username = 'Dave' 2 | console.log(username) 3 | 4 | let a: number = 12 5 | let b: string = '6' 6 | let c: number = 2 7 | 8 | console.log(a / b) 9 | 10 | console.log(c * b) -------------------------------------------------------------------------------- /lesson01/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | /* Projects */ 5 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 6 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 7 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 8 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 9 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 10 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 11 | /* Language and Environment */ 12 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 13 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 14 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 15 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 16 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 17 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 18 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 19 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 20 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 21 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 22 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 23 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 24 | /* Modules */ 25 | "module": "commonjs", /* Specify what module code is generated. */ 26 | "rootDir": "./src", /* Specify the root folder within your source files. */ 27 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 28 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 29 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 30 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 31 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 32 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 33 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 34 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 35 | // "resolveJsonModule": true, /* Enable importing .json files. */ 36 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 37 | /* JavaScript Support */ 38 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 39 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 40 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 41 | /* Emit */ 42 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 43 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 44 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 45 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 46 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 47 | "outDir": "./build/js", /* Specify an output folder for all emitted files. */ 48 | // "removeComments": true, /* Disable emitting comments. */ 49 | // "noEmit": true, /* Disable emitting files from a compilation. */ 50 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 51 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 52 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 53 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 54 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 55 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 56 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 57 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 58 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 59 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 60 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 61 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 62 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 63 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 64 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 65 | /* Interop Constraints */ 66 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 67 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 68 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 69 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 70 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 71 | /* Type Checking */ 72 | "strict": true, /* Enable all strict type-checking options. */ 73 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 74 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 75 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 76 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 77 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 78 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 79 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 80 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 81 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 82 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 83 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 84 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 85 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 86 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 87 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 88 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 89 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 90 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 91 | /* Completeness */ 92 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 93 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 94 | }, 95 | "include": [ 96 | "src" 97 | ] 98 | } -------------------------------------------------------------------------------- /lesson02/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson02/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | let myName = 'Dave'; 3 | let meaningOfLife; 4 | let isLoading; 5 | let album; 6 | myName = 'John'; 7 | meaningOfLife = 42; 8 | isLoading = true; 9 | album = 5150; 10 | const sum = (a, b) => { 11 | return a + b; 12 | }; 13 | let postId; 14 | let isActive; 15 | let re = /\w+/g; 16 | -------------------------------------------------------------------------------- /lesson02/src/main.ts: -------------------------------------------------------------------------------- 1 | let myName: string = 'Dave' 2 | let meaningOfLife: number; 3 | let isLoading: boolean; 4 | let album: any; 5 | 6 | myName = 'John' 7 | meaningOfLife = 42 8 | isLoading = true 9 | album = 5150 10 | 11 | const sum = (a: number, b: string) => { 12 | return a + b 13 | } 14 | 15 | let postId: string | number 16 | let isActive: number | boolean 17 | 18 | let re: RegExp = /\w+/g -------------------------------------------------------------------------------- /lesson02/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | /* Projects */ 5 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 6 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 7 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 8 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 9 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 10 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 11 | /* Language and Environment */ 12 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 13 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 14 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 15 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 16 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 17 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 18 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 19 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 20 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 21 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 22 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 23 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 24 | /* Modules */ 25 | "module": "commonjs", /* Specify what module code is generated. */ 26 | "rootDir": "./src", /* Specify the root folder within your source files. */ 27 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 28 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 29 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 30 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 31 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 32 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 33 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 34 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 35 | // "resolveJsonModule": true, /* Enable importing .json files. */ 36 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 37 | /* JavaScript Support */ 38 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 39 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 40 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 41 | /* Emit */ 42 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 43 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 44 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 45 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 46 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 47 | "outDir": "./build/js", /* Specify an output folder for all emitted files. */ 48 | // "removeComments": true, /* Disable emitting comments. */ 49 | // "noEmit": true, /* Disable emitting files from a compilation. */ 50 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 51 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 52 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 53 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 54 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 55 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 56 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 57 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 58 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 59 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 60 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 61 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 62 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 63 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 64 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 65 | /* Interop Constraints */ 66 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 67 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 68 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 69 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 70 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 71 | /* Type Checking */ 72 | "strict": true, /* Enable all strict type-checking options. */ 73 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 74 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 75 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 76 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 77 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 78 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 79 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 80 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 81 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 82 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 83 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 84 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 85 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 86 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 87 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 88 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 89 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 90 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 91 | /* Completeness */ 92 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 93 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 94 | }, 95 | "include": [ 96 | "src" 97 | ] 98 | } -------------------------------------------------------------------------------- /lesson03/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson03/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | let stringArr = ['one', 'hey', 'Dave']; 3 | let guitars = ['Strat', 'Les Paul', 5150]; 4 | let mixedData = ['EVH', 1984, true]; 5 | stringArr[0] = 'John'; 6 | stringArr.push('hey'); 7 | guitars[0] = 1984; 8 | guitars.unshift('Jim'); 9 | let test = []; 10 | let bands = []; 11 | bands.push('Van Halen'); 12 | // Tuple 13 | let myTuple = ['Dave', 42, true]; 14 | let mixed = ['John', 1, false]; 15 | myTuple[1] = 42; 16 | // Objects 17 | let myObj; 18 | myObj = []; 19 | console.log(typeof myObj); 20 | myObj = bands; 21 | myObj = {}; 22 | const exampleObj = { 23 | prop1: 'Dave', 24 | prop2: true, 25 | }; 26 | exampleObj.prop1 = 'John'; 27 | let evh = { 28 | name: 'Eddie', 29 | active: false, 30 | albums: [1984, 5150, 'OU812'] 31 | }; 32 | let jp = { 33 | active: true, 34 | albums: ['I', 'II', 'IV'] 35 | }; 36 | const greetGuitarist = (guitarist) => { 37 | if (guitarist.name) { 38 | return `Hello ${guitarist.name.toUpperCase()}!`; 39 | } 40 | return 'Hello!'; 41 | }; 42 | console.log(greetGuitarist(jp)); 43 | // Enums 44 | // "Unlike most TypeScript features, Enums are not a type-level addition to JavaScript but something added to the language and runtime." 45 | var Grade; 46 | (function (Grade) { 47 | Grade[Grade["U"] = 1] = "U"; 48 | Grade[Grade["D"] = 2] = "D"; 49 | Grade[Grade["C"] = 3] = "C"; 50 | Grade[Grade["B"] = 4] = "B"; 51 | Grade[Grade["A"] = 5] = "A"; 52 | })(Grade || (Grade = {})); 53 | console.log(Grade.U); 54 | -------------------------------------------------------------------------------- /lesson03/src/main.ts: -------------------------------------------------------------------------------- 1 | let stringArr = ["one", "hey", "Dave"]; 2 | 3 | let guitars = ["Strat", "Les Paul", 5150]; 4 | 5 | let mixedData = ["EVH", 1984, true]; 6 | 7 | stringArr[0] = "John"; 8 | stringArr.push("hey"); 9 | 10 | guitars[0] = 1984; 11 | guitars.unshift("Jim"); 12 | 13 | let test = []; 14 | let bands: string[] = []; 15 | bands.push("Van Halen"); 16 | 17 | // Tuple 18 | let myTuple: [string, number, boolean] = ["Dave", 42, true]; 19 | 20 | let mixed = ["John", 1, false]; 21 | 22 | myTuple[1] = 42; 23 | 24 | // Objects 25 | let myObj: object; 26 | myObj = []; 27 | console.log(typeof myObj); 28 | myObj = bands; 29 | myObj = {}; 30 | 31 | const exampleObj = { 32 | prop1: "Dave", 33 | prop2: true, 34 | }; 35 | 36 | exampleObj.prop1 = "John"; 37 | 38 | interface Guitarist { 39 | name?: string; 40 | active: boolean; 41 | albums: (string | number)[]; 42 | } 43 | 44 | let evh: Guitarist = { 45 | name: "Eddie", 46 | active: false, 47 | albums: [1984, 5150, "OU812"], 48 | }; 49 | 50 | let jp: Guitarist = { 51 | active: true, 52 | albums: ["I", "II", "IV"], 53 | }; 54 | 55 | const greetGuitarist = (guitarist: Guitarist) => { 56 | if (guitarist.name) { 57 | return `Hello ${guitarist.name.toUpperCase()}!`; 58 | } 59 | return "Hello!"; 60 | }; 61 | 62 | console.log(greetGuitarist(jp)); 63 | 64 | // Enums 65 | // "Unlike most TypeScript features, Enums are not a type-level addition to JavaScript but something added to the language and runtime." 66 | 67 | enum Grade { 68 | U = 1, 69 | D, 70 | C, 71 | B, 72 | A, 73 | } 74 | 75 | console.log(Grade.U); 76 | -------------------------------------------------------------------------------- /lesson03/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | /* Projects */ 5 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 6 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 7 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 8 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 9 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 10 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 11 | /* Language and Environment */ 12 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 13 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 14 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 15 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 16 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 17 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 18 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 19 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 20 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 21 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 22 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 23 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 24 | /* Modules */ 25 | "module": "commonjs", /* Specify what module code is generated. */ 26 | "rootDir": "./src", /* Specify the root folder within your source files. */ 27 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 28 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 29 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 30 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 31 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 32 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 33 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 34 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 35 | // "resolveJsonModule": true, /* Enable importing .json files. */ 36 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 37 | /* JavaScript Support */ 38 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 39 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 40 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 41 | /* Emit */ 42 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 43 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 44 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 45 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 46 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 47 | "outDir": "./build/js", /* Specify an output folder for all emitted files. */ 48 | // "removeComments": true, /* Disable emitting comments. */ 49 | // "noEmit": true, /* Disable emitting files from a compilation. */ 50 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 51 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 52 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 53 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 54 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 55 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 56 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 57 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 58 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 59 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 60 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 61 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 62 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 63 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 64 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 65 | /* Interop Constraints */ 66 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 67 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 68 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 69 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 70 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 71 | /* Type Checking */ 72 | "strict": true, /* Enable all strict type-checking options. */ 73 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 74 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 75 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 76 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 77 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 78 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 79 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 80 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 81 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 82 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 83 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 84 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 85 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 86 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 87 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 88 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 89 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 90 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 91 | /* Completeness */ 92 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 93 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 94 | }, 95 | "include": [ 96 | "src" 97 | ] 98 | } -------------------------------------------------------------------------------- /lesson04/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson04/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Literal types 3 | let myName; 4 | let userName; 5 | userName = 'Amy'; 6 | // functions 7 | const add = (a, b) => { 8 | return a + b; 9 | }; 10 | const logMsg = (message) => { 11 | console.log(message); 12 | }; 13 | logMsg('Hello!'); 14 | logMsg(add(2, 3)); 15 | let subtract = function (c, d) { 16 | return c - d; 17 | }; 18 | // interface mathFunction { 19 | // (a: number, b: number): number 20 | // } 21 | let multiply = function (c, d) { 22 | return c * d; 23 | }; 24 | logMsg(multiply(2, 2)); 25 | // optional parameters 26 | const addAll = (a, b, c) => { 27 | if (typeof c !== 'undefined') { 28 | return a + b + c; 29 | } 30 | return a + b; 31 | }; 32 | // default param value 33 | const sumAll = (a = 10, b, c = 2) => { 34 | return a + b + c; 35 | }; 36 | logMsg(addAll(2, 3, 2)); 37 | logMsg(addAll(2, 3)); 38 | logMsg(sumAll(2, 3)); 39 | logMsg(sumAll(undefined, 3)); 40 | // Rest Parameters 41 | const total = (a, ...nums) => { 42 | return a + nums.reduce((prev, curr) => prev + curr); 43 | }; 44 | logMsg(total(10, 2, 3)); 45 | const createError = (errMsg) => { 46 | throw new Error(errMsg); 47 | }; 48 | const infinite = () => { 49 | let i = 1; 50 | while (true) { 51 | i++; 52 | if (i > 100) 53 | break; 54 | } 55 | }; 56 | // custom type guard 57 | const isNumber = (value) => { 58 | return typeof value === 'number' 59 | ? true : false; 60 | }; 61 | // use of the never type 62 | const numberOrString = (value) => { 63 | if (typeof value === 'string') 64 | return 'string'; 65 | if (isNumber(value)) 66 | return 'number'; 67 | return createError('This should never happen!'); 68 | }; 69 | -------------------------------------------------------------------------------- /lesson04/src/main.ts: -------------------------------------------------------------------------------- 1 | // Type Aliases 2 | type stringOrNumber = string | number 3 | 4 | type stringOrNumberArray = (string | number)[] 5 | 6 | type Guitarist = { 7 | name?: string, 8 | active: boolean, 9 | albums: stringOrNumberArray 10 | } 11 | 12 | type UserId = stringOrNumber 13 | 14 | // Literal types 15 | let myName: 'Dave' 16 | 17 | let userName: 'Dave' | 'John' | 'Amy' 18 | userName = 'Amy' 19 | 20 | // functions 21 | const add = (a: number, b: number): number => { 22 | return a + b 23 | } 24 | 25 | const logMsg = (message: any): void => { 26 | console.log(message) 27 | } 28 | 29 | logMsg('Hello!') 30 | logMsg(add(2, 3)) 31 | 32 | let subtract = function (c: number, d: number): number { 33 | return c - d 34 | } 35 | 36 | type mathFunction = (a: number, b: number) => number 37 | // interface mathFunction { 38 | // (a: number, b: number): number 39 | // } 40 | 41 | let multiply: mathFunction = function (c, d) { 42 | return c * d 43 | } 44 | 45 | logMsg(multiply(2, 2)) 46 | 47 | // optional parameters 48 | const addAll = (a: number, b: number, c?: number): number => { 49 | if (typeof c !== 'undefined') { 50 | return a + b + c 51 | } 52 | return a + b 53 | } 54 | 55 | // default param value 56 | const sumAll = (a: number = 10, b: number, c: number = 2): number => { 57 | return a + b + c 58 | } 59 | 60 | logMsg(addAll(2, 3, 2)) 61 | logMsg(addAll(2, 3)) 62 | logMsg(sumAll(2, 3)) 63 | logMsg(sumAll(undefined, 3)) 64 | 65 | // Rest Parameters 66 | const total = (a: number, ...nums: number[]): number => { 67 | return a + nums.reduce((prev, curr) => prev + curr) 68 | } 69 | 70 | logMsg(total(10, 2, 3)) 71 | 72 | const createError = (errMsg: string): never => { 73 | throw new Error(errMsg) 74 | } 75 | 76 | const infinite = () => { 77 | let i: number = 1 78 | while (true) { 79 | i++ 80 | if (i > 100) break 81 | } 82 | } 83 | 84 | // custom type guard 85 | const isNumber = (value: any): boolean => { 86 | return typeof value === 'number' 87 | ? true : false 88 | } 89 | 90 | // use of the never type 91 | const numberOrString = (value: number | string): string => { 92 | if (typeof value === 'string') return 'string' 93 | if (isNumber(value)) return 'number' 94 | return createError('This should never happen!') 95 | } -------------------------------------------------------------------------------- /lesson04/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | /* Projects */ 5 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 6 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 7 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 8 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 9 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 10 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 11 | /* Language and Environment */ 12 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 13 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 14 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 15 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 16 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 17 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 18 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 19 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 20 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 21 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 22 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 23 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 24 | /* Modules */ 25 | "module": "commonjs", /* Specify what module code is generated. */ 26 | "rootDir": "./src", /* Specify the root folder within your source files. */ 27 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 28 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 29 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 30 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 31 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 32 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 33 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 34 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 35 | // "resolveJsonModule": true, /* Enable importing .json files. */ 36 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 37 | /* JavaScript Support */ 38 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 39 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 40 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 41 | /* Emit */ 42 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 43 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 44 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 45 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 46 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 47 | "outDir": "./build/js", /* Specify an output folder for all emitted files. */ 48 | // "removeComments": true, /* Disable emitting comments. */ 49 | // "noEmit": true, /* Disable emitting files from a compilation. */ 50 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 51 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 52 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 53 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 54 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 55 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 56 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 57 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 58 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 59 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 60 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 61 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 62 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 63 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 64 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 65 | /* Interop Constraints */ 66 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 67 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 68 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 69 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 70 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 71 | /* Type Checking */ 72 | "strict": true, /* Enable all strict type-checking options. */ 73 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 74 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 75 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 76 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 77 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 78 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 79 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 80 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 81 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 82 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 83 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 84 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 85 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 86 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 87 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 88 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 89 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 90 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 91 | /* Completeness */ 92 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 93 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 94 | }, 95 | "include": [ 96 | "src" 97 | ] 98 | } -------------------------------------------------------------------------------- /lesson05/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Copyright 9 | 20 | 21 | 22 | 23 | 24 |

Copyright ©

25 | 26 | 27 | -------------------------------------------------------------------------------- /lesson05/build/js/copyright.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Original JS code 3 | // const year = document.getElementById("year") 4 | // const thisYear = new Date().getFullYear() 5 | // year.setAttribute("datetime", thisYear) 6 | // year.textContent = thisYear 7 | // 1st variation: 8 | // let year: HTMLElement | null 9 | // year = document.getElementById("year") 10 | // let thisYear: string 11 | // thisYear = new Date().getFullYear().toString() 12 | // if (year) { 13 | // year.setAttribute("datetime", thisYear) 14 | // year.textContent = thisYear 15 | // } 16 | // 2nd variation: 17 | const year = document.getElementById("year"); 18 | const thisYear = new Date().getFullYear().toString(); 19 | year.setAttribute("datetime", thisYear); 20 | year.textContent = thisYear; 21 | -------------------------------------------------------------------------------- /lesson05/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // convert to more or less specific 3 | let a = 'hello'; 4 | let b = a; // less specific 5 | let c = a; // more specific 6 | let d = 'world'; 7 | let e = 'world'; 8 | const addOrConcat = (a, b, c) => { 9 | if (c === 'add') 10 | return a + b; 11 | return '' + a + b; 12 | }; 13 | let myVal = addOrConcat(2, 2, 'concat'); 14 | // Be careful! TS sees no problem - but a string is returned 15 | let nextVal = addOrConcat(2, 2, 'concat'); 16 | //10 as string 17 | 10; 18 | // The DOM 19 | const img = document.querySelector('img'); 20 | const myImg = document.getElementById('#img'); 21 | const nextImg = document.getElementById('#img'); 22 | img.src; 23 | myImg.src; 24 | -------------------------------------------------------------------------------- /lesson05/src/copyright.ts: -------------------------------------------------------------------------------- 1 | // Original JS code 2 | // const year = document.getElementById("year") 3 | // const thisYear = new Date().getFullYear() 4 | // year.setAttribute("datetime", thisYear) 5 | // year.textContent = thisYear 6 | 7 | // 1st variation: (Beginner) 8 | // let year: HTMLElement | null 9 | // year = document.getElementById("year") 10 | // let thisYear: string 11 | // thisYear = new Date().getFullYear().toString() 12 | // if (year) { 13 | // year.setAttribute("datetime", thisYear) 14 | // year.textContent = thisYear 15 | // } 16 | 17 | // 2nd variation: (with Type Assertion) 18 | const year = document.getElementById("year") as HTMLSpanElement 19 | const thisYear: string = new Date().getFullYear().toString() 20 | year.setAttribute("datetime", thisYear) 21 | year.textContent = thisYear 22 | 23 | -------------------------------------------------------------------------------- /lesson05/src/main.ts: -------------------------------------------------------------------------------- 1 | type One = string 2 | type Two = string | number 3 | type Three = 'hello' 4 | 5 | // convert to more or less specific 6 | let a: One = 'hello' 7 | let b = a as Two // less specific 8 | let c = a as Three // more specific 9 | 10 | let d = 'world' 11 | let e = 'world' 12 | 13 | const addOrConcat = (a: number, b: number, c: 'add' | 'concat'): number | string => { 14 | if (c === 'add') return a + b 15 | return '' + a + b 16 | } 17 | 18 | let myVal: string = addOrConcat(2, 2, 'concat') as string 19 | 20 | // Be careful! TS sees no problem - but a string is returned 21 | let nextVal: number = addOrConcat(2, 2, 'concat') as number 22 | 23 | //10 as string 24 | (10 as unknown) as string 25 | 26 | // The DOM 27 | const img = document.querySelector('img')! 28 | const myImg = document.getElementById('#img') as HTMLImageElement 29 | const nextImg = document.getElementById('#img') 30 | 31 | img.src 32 | myImg.src -------------------------------------------------------------------------------- /lesson05/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | /* Projects */ 5 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 6 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 7 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 8 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 9 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 10 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 11 | /* Language and Environment */ 12 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 13 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 14 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 15 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 16 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 17 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 18 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 19 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 20 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 21 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 22 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 23 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 24 | /* Modules */ 25 | "module": "commonjs", /* Specify what module code is generated. */ 26 | "rootDir": "./src", /* Specify the root folder within your source files. */ 27 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 28 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 29 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 30 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 31 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 32 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 33 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 34 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 35 | // "resolveJsonModule": true, /* Enable importing .json files. */ 36 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 37 | /* JavaScript Support */ 38 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 39 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 40 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 41 | /* Emit */ 42 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 43 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 44 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 45 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 46 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 47 | "outDir": "./build/js", /* Specify an output folder for all emitted files. */ 48 | // "removeComments": true, /* Disable emitting comments. */ 49 | // "noEmit": true, /* Disable emitting files from a compilation. */ 50 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 51 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 52 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 53 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 54 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 55 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 56 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 57 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 58 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 59 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 60 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 61 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 62 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 63 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 64 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 65 | /* Interop Constraints */ 66 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 67 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 68 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 69 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 70 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 71 | /* Type Checking */ 72 | "strict": true, /* Enable all strict type-checking options. */ 73 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 74 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 75 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 76 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 77 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 78 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 79 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 80 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 81 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 82 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 83 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 84 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 85 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 86 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 87 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 88 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 89 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 90 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 91 | /* Completeness */ 92 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 93 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 94 | }, 95 | "include": [ 96 | "src" 97 | ] 98 | } -------------------------------------------------------------------------------- /lesson06/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Example 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson06/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | class Coder { 3 | constructor(name, music, age, lang = 'Typescript') { 4 | this.name = name; 5 | this.music = music; 6 | this.age = age; 7 | this.lang = lang; 8 | this.name = name; 9 | this.music = music; 10 | this.age = age; 11 | this.lang = lang; 12 | } 13 | getAge() { 14 | return `Hello, I'm ${this.age}`; 15 | } 16 | } 17 | const Dave = new Coder('Dave', 'Rock', 42); 18 | console.log(Dave.getAge()); 19 | // console.log(Dave.age) 20 | // console.log(Dave.lang) 21 | class WebDev extends Coder { 22 | constructor(computer, name, music, age) { 23 | super(name, music, age); 24 | this.computer = computer; 25 | this.computer = computer; 26 | } 27 | getLang() { 28 | return `I write ${this.lang}`; 29 | } 30 | } 31 | const Sara = new WebDev('Mac', 'Sara', 'Lofi', 25); 32 | console.log(Sara.getLang()); 33 | class Guitarist { 34 | constructor(name, instrument) { 35 | this.name = name; 36 | this.instrument = instrument; 37 | } 38 | play(action) { 39 | return `${this.name} ${action} the ${this.instrument}`; 40 | } 41 | } 42 | const Page = new Guitarist('Jimmy', 'guitar'); 43 | console.log(Page.play('strums')); 44 | ////////////////////////////////////// 45 | class Peeps { 46 | constructor(name) { 47 | this.name = name; 48 | this.name = name; 49 | this.id = ++Peeps.count; 50 | } 51 | static getCount() { 52 | return Peeps.count; 53 | } 54 | } 55 | Peeps.count = 0; 56 | const John = new Peeps('John'); 57 | const Steve = new Peeps('Steve'); 58 | const Amy = new Peeps('Amy'); 59 | console.log(Amy.id); 60 | console.log(Steve.id); 61 | console.log(John.id); 62 | console.log(Peeps.count); 63 | ////////////////////////////////// 64 | class Bands { 65 | constructor() { 66 | this.dataState = []; 67 | } 68 | get data() { 69 | return this.dataState; 70 | } 71 | set data(value) { 72 | if (Array.isArray(value) && value.every(el => typeof el === 'string')) { 73 | this.dataState = value; 74 | return; 75 | } 76 | else 77 | throw new Error('Param is not an array of strings'); 78 | } 79 | } 80 | const MyBands = new Bands(); 81 | MyBands.data = ['Neil Young', 'Led Zep']; 82 | console.log(MyBands.data); 83 | MyBands.data = [...MyBands.data, 'ZZ Top']; 84 | console.log(MyBands.data); 85 | MyBands.data = ['Van Halen', 5150]; 86 | -------------------------------------------------------------------------------- /lesson06/src/main.ts: -------------------------------------------------------------------------------- 1 | class Coder { 2 | 3 | secondLang!: string 4 | 5 | constructor( 6 | public readonly name: string, 7 | public music: string, 8 | private age: number, 9 | protected lang: string = 'Typescript' 10 | ) { 11 | this.name = name 12 | this.music = music 13 | this.age = age 14 | this.lang = lang 15 | } 16 | 17 | public getAge() { 18 | return `Hello, I'm ${this.age}` 19 | } 20 | } 21 | 22 | const Dave = new Coder('Dave', 'Rock', 42) 23 | console.log(Dave.getAge()) 24 | // console.log(Dave.age) 25 | // console.log(Dave.lang) 26 | 27 | class WebDev extends Coder { 28 | constructor( 29 | public computer: string, 30 | name: string, 31 | music: string, 32 | age: number, 33 | ) { 34 | super(name, music, age) 35 | this.computer = computer 36 | } 37 | 38 | public getLang() { 39 | return `I write ${this.lang}` 40 | } 41 | } 42 | 43 | const Sara = new WebDev('Mac', 'Sara', 'Lofi', 25) 44 | console.log(Sara.getLang()) 45 | // console.log(Sara.age) 46 | // console.log(Sara.lang) 47 | ///////////////////////////////////// 48 | 49 | interface Musician { 50 | name: string, 51 | instrument: string, 52 | play(action: string): string 53 | } 54 | 55 | class Guitarist implements Musician { 56 | name: string 57 | instrument: string 58 | 59 | constructor(name: string, instrument: string) { 60 | this.name = name 61 | this.instrument = instrument 62 | } 63 | 64 | play(action: string) { 65 | return `${this.name} ${action} the ${this.instrument}` 66 | } 67 | } 68 | 69 | const Page = new Guitarist('Jimmy', 'guitar') 70 | console.log(Page.play('strums')) 71 | ////////////////////////////////////// 72 | 73 | class Peeps { 74 | static count: number = 0 75 | 76 | static getCount(): number { 77 | return Peeps.count 78 | } 79 | 80 | public id: number 81 | 82 | constructor(public name: string) { 83 | this.name = name 84 | this.id = ++Peeps.count 85 | } 86 | } 87 | 88 | const John = new Peeps('John') 89 | const Steve = new Peeps('Steve') 90 | const Amy = new Peeps('Amy') 91 | 92 | console.log(Amy.id) 93 | console.log(Steve.id) 94 | console.log(John.id) 95 | console.log(Peeps.count) 96 | ////////////////////////////////// 97 | 98 | class Bands { 99 | private dataState: string[] 100 | 101 | constructor() { 102 | this.dataState = [] 103 | } 104 | 105 | public get data(): string[] { 106 | return this.dataState 107 | } 108 | 109 | public set data(value: string[]) { 110 | if (Array.isArray(value) && value.every(el => typeof el === 'string')) { 111 | this.dataState = value 112 | return 113 | } else throw new Error('Param is not an array of strings') 114 | } 115 | } 116 | 117 | const MyBands = new Bands() 118 | MyBands.data = ['Neil Young', 'Led Zep'] 119 | console.log(MyBands.data) 120 | MyBands.data = [...MyBands.data, 'ZZ Top'] 121 | console.log(MyBands.data) 122 | MyBands.data = ['Van Halen', 5150] // must be string data -------------------------------------------------------------------------------- /lesson07/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Example 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson07/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Index Signatures 3 | const todaysTransactions = { 4 | Pizza: -10, 5 | Books: -5, 6 | Job: 50, 7 | }; 8 | console.log(todaysTransactions.Pizza); 9 | console.log(todaysTransactions['Pizza']); 10 | let prop = 'Pizza'; 11 | console.log(todaysTransactions[prop]); 12 | const todaysNet = (transactions) => { 13 | let total = 0; 14 | for (const transaction in transactions) { 15 | total += transactions[transaction]; 16 | } 17 | return total; 18 | }; 19 | console.log(todaysNet(todaysTransactions)); 20 | //todaysTransactions.Pizza = 40 21 | console.log(todaysTransactions['Dave']); // undefined 22 | const student = { 23 | name: "Doug", 24 | GPA: 3.5, 25 | classes: [100, 200] 26 | }; 27 | // console.log(student.test) 28 | for (const key in student) { 29 | console.log(`${key}: ${student[key]}`); 30 | } 31 | Object.keys(student).map(key => { 32 | console.log(student[key]); 33 | }); 34 | const logStudentKey = (student, key) => { 35 | console.log(`Student ${key}: ${student[key]}`); 36 | }; 37 | logStudentKey(student, 'name'); 38 | const monthlyIncomes = { 39 | salary: 500, 40 | bonus: 100, 41 | sidehustle: 250 42 | }; 43 | for (const revenue in monthlyIncomes) { 44 | console.log(monthlyIncomes[revenue]); 45 | } 46 | -------------------------------------------------------------------------------- /lesson07/src/main.ts: -------------------------------------------------------------------------------- 1 | // Index Signatures 2 | 3 | // interface TransactionObj { 4 | // readonly [index: string]: number 5 | // } 6 | 7 | interface TransactionObj { 8 | readonly [index: string]: number 9 | Pizza: number, 10 | Books: number, 11 | Job: number 12 | } 13 | 14 | const todaysTransactions: TransactionObj = { 15 | Pizza: -10, 16 | Books: -5, 17 | Job: 50, 18 | } 19 | 20 | console.log(todaysTransactions.Pizza) 21 | console.log(todaysTransactions['Pizza']) 22 | 23 | let prop: string = 'Pizza' 24 | console.log(todaysTransactions[prop]) 25 | 26 | const todaysNet = (transactions: TransactionObj): number => { 27 | let total = 0 28 | for (const transaction in transactions) { 29 | total += transactions[transaction] 30 | } 31 | return total 32 | } 33 | 34 | console.log(todaysNet(todaysTransactions)) 35 | 36 | //todaysTransactions.Pizza = 40 37 | 38 | console.log(todaysTransactions['Dave']) // undefined 39 | 40 | /////////////////////////////////// 41 | 42 | interface Student { 43 | //[key: string]: string | number | number[] | undefined 44 | name: string, 45 | GPA: number, 46 | classes?: number[] 47 | } 48 | 49 | const student: Student = { 50 | name: "Doug", 51 | GPA: 3.5, 52 | classes: [100, 200] 53 | } 54 | 55 | // console.log(student.test) 56 | 57 | for (const key in student) { 58 | console.log(`${key}: ${student[key as keyof Student]}`) 59 | } 60 | 61 | Object.keys(student).map(key => { 62 | console.log(student[key as keyof typeof student]) 63 | }) 64 | 65 | const logStudentKey = (student: Student, key: keyof Student): void => { 66 | console.log(`Student ${key}: ${student[key]}`) 67 | } 68 | 69 | logStudentKey(student, 'name') 70 | 71 | ///////////////////////////////// 72 | 73 | // interface Incomes { 74 | // [key: string]: number 75 | // } 76 | 77 | type Streams = 'salary' | 'bonus' | 'sidehustle' 78 | 79 | type Incomes = Record 80 | 81 | const monthlyIncomes: Incomes = { 82 | salary: 500, 83 | bonus: 100, 84 | sidehustle: 250 85 | } 86 | 87 | for (const revenue in monthlyIncomes) { 88 | console.log(monthlyIncomes[revenue as keyof Incomes]) 89 | } -------------------------------------------------------------------------------- /lesson08/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Example 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson08/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const echo = (arg) => arg; 3 | const isObj = (arg) => { 4 | return (typeof arg === 'object' && !Array.isArray(arg) && arg !== null); 5 | }; 6 | console.log(isObj(true)); 7 | console.log(isObj('John')); 8 | console.log(isObj([1, 2, 3])); 9 | console.log(isObj({ name: 'John' })); 10 | console.log(isObj(null)); 11 | const isTrue = (arg) => { 12 | if (Array.isArray(arg) && !arg.length) { 13 | return { arg, is: false }; 14 | } 15 | if (isObj(arg) && !Object.keys(arg).length) { 16 | return { arg, is: false }; 17 | } 18 | return { arg, is: !!arg }; 19 | }; 20 | console.log(isTrue(false)); 21 | console.log(isTrue(0)); 22 | console.log(isTrue(true)); 23 | console.log(isTrue(1)); 24 | console.log(isTrue('Dave')); 25 | console.log(isTrue('')); 26 | console.log(isTrue(null)); 27 | console.log(isTrue(undefined)); 28 | console.log(isTrue({})); // modified 29 | console.log(isTrue({ name: 'Dave' })); 30 | console.log(isTrue([])); // modified 31 | console.log(isTrue([1, 2, 3])); 32 | console.log(isTrue(NaN)); 33 | console.log(isTrue(-0)); 34 | const checkBoolValue = (arg) => { 35 | if (Array.isArray(arg) && !arg.length) { 36 | return { value: arg, is: false }; 37 | } 38 | if (isObj(arg) && !Object.keys(arg).length) { 39 | return { value: arg, is: false }; 40 | } 41 | return { value: arg, is: !!arg }; 42 | }; 43 | const processUser = (user) => { 44 | // process the user with logic here 45 | return user; 46 | }; 47 | console.log(processUser({ id: 1, name: 'Dave' })); 48 | //console.log(processUser({ name: 'Dave'})) 49 | const getUsersProperty = (users, key) => { 50 | return users.map(user => user[key]); 51 | }; 52 | const usersArray = [ 53 | { 54 | "id": 1, 55 | "name": "Leanne Graham", 56 | "username": "Bret", 57 | "email": "Sincere@april.biz", 58 | "address": { 59 | "street": "Kulas Light", 60 | "suite": "Apt. 556", 61 | "city": "Gwenborough", 62 | "zipcode": "92998-3874", 63 | "geo": { 64 | "lat": "-37.3159", 65 | "lng": "81.1496" 66 | } 67 | }, 68 | "phone": "1-770-736-8031 x56442", 69 | "website": "hildegard.org", 70 | "company": { 71 | "name": "Romaguera-Crona", 72 | "catchPhrase": "Multi-layered client-server neural-net", 73 | "bs": "harness real-time e-markets" 74 | } 75 | }, 76 | { 77 | "id": 2, 78 | "name": "Ervin Howell", 79 | "username": "Antonette", 80 | "email": "Shanna@melissa.tv", 81 | "address": { 82 | "street": "Victor Plains", 83 | "suite": "Suite 879", 84 | "city": "Wisokyburgh", 85 | "zipcode": "90566-7771", 86 | "geo": { 87 | "lat": "-43.9509", 88 | "lng": "-34.4618" 89 | } 90 | }, 91 | "phone": "010-692-6593 x09125", 92 | "website": "anastasia.net", 93 | "company": { 94 | "name": "Deckow-Crist", 95 | "catchPhrase": "Proactive didactic contingency", 96 | "bs": "synergize scalable supply-chains" 97 | } 98 | }, 99 | ]; 100 | console.log(getUsersProperty(usersArray, "email")); 101 | console.log(getUsersProperty(usersArray, "username")); 102 | class StateObject { 103 | constructor(value) { 104 | this.data = value; 105 | } 106 | get state() { 107 | return this.data; 108 | } 109 | set state(value) { 110 | this.data = value; 111 | } 112 | } 113 | const store = new StateObject("John"); 114 | console.log(store.state); 115 | store.state = "Dave"; 116 | //store.state = 12 117 | const myState = new StateObject([15]); 118 | myState.state = ['Dave', 42, true]; 119 | console.log(myState.state); 120 | -------------------------------------------------------------------------------- /lesson08/src/main.ts: -------------------------------------------------------------------------------- 1 | const echo = (arg: T): T => arg 2 | 3 | ////////////////////////////////// 4 | 5 | const isObj = (arg: T): boolean => { 6 | return (typeof arg === 'object' && !Array.isArray(arg) && arg !== null) 7 | } 8 | 9 | console.log(isObj(true)) 10 | console.log(isObj('John')) 11 | console.log(isObj([1, 2, 3])) 12 | console.log(isObj({ name: 'John' })) 13 | console.log(isObj(null)) 14 | 15 | /////////////////////////////////// 16 | 17 | const isTrue = (arg: T): { arg: T, is: boolean } => { 18 | if (Array.isArray(arg) && !arg.length) { 19 | return { arg, is: false } 20 | } 21 | if (isObj(arg) && !Object.keys(arg as keyof T).length) { 22 | return { arg, is: false } 23 | } 24 | return { arg, is: !!arg } 25 | } 26 | 27 | console.log(isTrue(false)) 28 | console.log(isTrue(0)) 29 | console.log(isTrue(true)) 30 | console.log(isTrue(1)) 31 | console.log(isTrue('Dave')) 32 | console.log(isTrue('')) 33 | console.log(isTrue(null)) 34 | console.log(isTrue(undefined)) 35 | console.log(isTrue({})) // modified 36 | console.log(isTrue({ name: 'Dave' })) 37 | console.log(isTrue([])) // modified 38 | console.log(isTrue([1, 2, 3])) 39 | console.log(isTrue(NaN)) 40 | console.log(isTrue(-0)) 41 | 42 | //////////////////////////////////// 43 | 44 | interface BoolCheck { 45 | value: T, 46 | is: boolean, 47 | } 48 | 49 | const checkBoolValue = (arg: T): BoolCheck => { 50 | if (Array.isArray(arg) && !arg.length) { 51 | return { value: arg, is: false } 52 | } 53 | if (isObj(arg) && !Object.keys(arg as keyof T).length) { 54 | return { value: arg, is: false } 55 | } 56 | return { value: arg, is: !!arg } 57 | } 58 | 59 | ////////////////////////////////////// 60 | 61 | 62 | interface HasID { 63 | id: number 64 | } 65 | 66 | const processUser = (user: T): T => { 67 | // process the user with logic here 68 | return user 69 | } 70 | 71 | console.log(processUser({ id: 1, name: 'Dave' })) 72 | //console.log(processUser({ name: 'Dave'})) 73 | 74 | /////////////////////////////////////// 75 | 76 | 77 | const getUsersProperty = (users: T[], key: K): T[K][] => { 78 | return users.map(user => user[key]) 79 | } 80 | 81 | const usersArray = [ 82 | { 83 | "id": 1, 84 | "name": "Leanne Graham", 85 | "username": "Bret", 86 | "email": "Sincere@april.biz", 87 | "address": { 88 | "street": "Kulas Light", 89 | "suite": "Apt. 556", 90 | "city": "Gwenborough", 91 | "zipcode": "92998-3874", 92 | "geo": { 93 | "lat": "-37.3159", 94 | "lng": "81.1496" 95 | } 96 | }, 97 | "phone": "1-770-736-8031 x56442", 98 | "website": "hildegard.org", 99 | "company": { 100 | "name": "Romaguera-Crona", 101 | "catchPhrase": "Multi-layered client-server neural-net", 102 | "bs": "harness real-time e-markets" 103 | } 104 | }, 105 | { 106 | "id": 2, 107 | "name": "Ervin Howell", 108 | "username": "Antonette", 109 | "email": "Shanna@melissa.tv", 110 | "address": { 111 | "street": "Victor Plains", 112 | "suite": "Suite 879", 113 | "city": "Wisokyburgh", 114 | "zipcode": "90566-7771", 115 | "geo": { 116 | "lat": "-43.9509", 117 | "lng": "-34.4618" 118 | } 119 | }, 120 | "phone": "010-692-6593 x09125", 121 | "website": "anastasia.net", 122 | "company": { 123 | "name": "Deckow-Crist", 124 | "catchPhrase": "Proactive didactic contingency", 125 | "bs": "synergize scalable supply-chains" 126 | } 127 | }, 128 | ] 129 | 130 | console.log(getUsersProperty(usersArray, "email")) 131 | console.log(getUsersProperty(usersArray, "username")) 132 | 133 | /////////////////////////////////////// 134 | 135 | class StateObject { 136 | private data: T 137 | 138 | constructor(value: T) { 139 | this.data = value 140 | } 141 | 142 | get state(): T { 143 | return this.data 144 | } 145 | 146 | set state(value: T) { 147 | this.data = value 148 | } 149 | } 150 | 151 | const store = new StateObject("John") 152 | console.log(store.state) 153 | store.state = "Dave" 154 | //store.state = 12 155 | 156 | const myState = new StateObject<(string | number | boolean)[]>([15]) 157 | myState.state = ['Dave', 42, true] 158 | console.log(myState.state) -------------------------------------------------------------------------------- /lesson09/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Example 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson09/build/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Utility Types 3 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 4 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 5 | return new (P || (P = Promise))(function (resolve, reject) { 6 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 7 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 8 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 9 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 10 | }); 11 | }; 12 | const updateAssignment = (assign, propsToUpdate) => { 13 | return Object.assign(Object.assign({}, assign), propsToUpdate); 14 | }; 15 | const assign1 = { 16 | studentId: "compsci123", 17 | title: "Final Project", 18 | grade: 0, 19 | }; 20 | console.log(updateAssignment(assign1, { grade: 95 })); 21 | const assignGraded = updateAssignment(assign1, { grade: 95 }); 22 | // Required and Readonly 23 | const recordAssignment = (assign) => { 24 | // send to database, etc. 25 | return assign; 26 | }; 27 | const assignVerified = Object.assign(Object.assign({}, assignGraded), { verified: true }); 28 | recordAssignment(Object.assign(Object.assign({}, assignGraded), { verified: true })); 29 | // Record 30 | const hexColorMap = { 31 | red: "FF0000", 32 | green: "00FF00", 33 | blue: "0000FF", 34 | }; 35 | const finalGrades = { 36 | Sara: "B", 37 | Kelly: "U" 38 | }; 39 | const gradeData = { 40 | Sara: { assign1: 85, assign2: 93 }, 41 | Kelly: { assign1: 76, assign2: 15 }, 42 | }; 43 | const score = { 44 | studentId: "k123", 45 | grade: 85, 46 | }; 47 | const preview = { 48 | studentId: "k123", 49 | title: "Final Project", 50 | }; 51 | // ReturnType 52 | //type newAssign = { title: string, points: number } 53 | const createNewAssign = (title, points) => { 54 | return { title, points }; 55 | }; 56 | const tsAssign = createNewAssign("Utility Types", 100); 57 | console.log(tsAssign); 58 | const assignArgs = ["Generics", 100]; 59 | const tsAssign2 = createNewAssign(...assignArgs); 60 | console.log(tsAssign2); 61 | const fetchUsers = () => __awaiter(void 0, void 0, void 0, function* () { 62 | const data = yield fetch('https://jsonplaceholder.typicode.com/users').then(res => { 63 | return res.json(); 64 | }).catch(err => { 65 | if (err instanceof Error) 66 | console.log(err.message); 67 | }); 68 | return data; 69 | }); 70 | fetchUsers().then(users => console.log(users)); 71 | -------------------------------------------------------------------------------- /lesson09/src/main.ts: -------------------------------------------------------------------------------- 1 | // Utility Types 2 | 3 | // Partial 4 | 5 | interface Assignment { 6 | studentId: string, 7 | title: string, 8 | grade: number, 9 | verified?: boolean, 10 | } 11 | 12 | const updateAssignment = (assign: Assignment, propsToUpdate: Partial): Assignment => { 13 | return { ...assign, ...propsToUpdate } 14 | } 15 | 16 | const assign1: Assignment = { 17 | studentId: "compsci123", 18 | title: "Final Project", 19 | grade: 0, 20 | } 21 | 22 | console.log(updateAssignment(assign1, { grade: 95 })) 23 | const assignGraded: Assignment = updateAssignment(assign1, { grade: 95 }) 24 | 25 | 26 | // Required and Readonly 27 | 28 | const recordAssignment = (assign: Required): Assignment => { 29 | // send to database, etc. 30 | return assign 31 | } 32 | 33 | const assignVerified: Readonly = { ...assignGraded, verified: true } 34 | 35 | // NOTE: assignVerified won't work with recordAssignment! 36 | // Why? Try it and see what TS tells you :) 37 | 38 | recordAssignment({ ...assignGraded, verified: true }) 39 | 40 | // Record 41 | const hexColorMap: Record = { 42 | red: "FF0000", 43 | green: "00FF00", 44 | blue: "0000FF", 45 | } 46 | 47 | type Students = "Sara" | "Kelly" 48 | type LetterGrades = "A" | "B" | "C" | "D" | "U" 49 | 50 | const finalGrades: Record = { 51 | Sara: "B", 52 | Kelly: "U" 53 | } 54 | 55 | interface Grades { 56 | assign1: number, 57 | assign2: number, 58 | } 59 | 60 | const gradeData: Record = { 61 | Sara: { assign1: 85, assign2: 93 }, 62 | Kelly: { assign1: 76, assign2: 15 }, 63 | } 64 | 65 | // Pick and Omit 66 | 67 | type AssignResult = Pick 68 | 69 | const score: AssignResult = { 70 | studentId: "k123", 71 | grade: 85, 72 | } 73 | 74 | type AssignPreview = Omit 75 | 76 | const preview: AssignPreview = { 77 | studentId: "k123", 78 | title: "Final Project", 79 | } 80 | 81 | // Exclude and Extract 82 | 83 | type adjustedGrade = Exclude 84 | 85 | type highGrades = Extract 86 | 87 | // Nonnullable 88 | 89 | type AllPossibleGrades = 'Dave' | 'John' | null | undefined 90 | type NamesOnly = NonNullable 91 | 92 | // ReturnType 93 | 94 | //type newAssign = { title: string, points: number } 95 | 96 | const createNewAssign = (title: string, points: number) => { 97 | return { title, points } 98 | } 99 | 100 | type NewAssign = ReturnType 101 | 102 | const tsAssign: NewAssign = createNewAssign("Utility Types", 100) 103 | console.log(tsAssign) 104 | 105 | // Parameters 106 | 107 | type AssignParams = Parameters 108 | 109 | const assignArgs: AssignParams = ["Generics", 100] 110 | 111 | const tsAssign2: NewAssign = createNewAssign(...assignArgs) 112 | console.log(tsAssign2) 113 | 114 | // Awaited - helps us with the ReturnType of a Promise 115 | 116 | interface User { 117 | id: number, 118 | name: string, 119 | username: string, 120 | email: string, 121 | } 122 | 123 | const fetchUsers = async (): Promise => { 124 | 125 | const data = await fetch( 126 | 'https://jsonplaceholder.typicode.com/users' 127 | ).then(res => { 128 | return res.json() 129 | }).catch(err => { 130 | if (err instanceof Error) console.log(err.message) 131 | }) 132 | return data 133 | } 134 | 135 | type FetchUsersReturnType = Awaited> 136 | 137 | fetchUsers().then(users => console.log(users)) -------------------------------------------------------------------------------- /lesson11/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lesson11/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | My List 9 | 10 | 11 | 12 | 13 | 14 |
15 |

My List

16 | 17 |
18 |

New Item Entry

19 |
20 | 21 | 23 | 26 |
27 |
28 | 29 |
30 |
31 |

List

32 | 36 |
37 |
38 |
    39 | 54 |
55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /lesson11/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lesson11", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^4.6.4", 13 | "vite": "^3.2.3" 14 | } 15 | } -------------------------------------------------------------------------------- /lesson11/src/css/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | .offscreen { 10 | position: absolute; 11 | left: -10000px; 12 | } 13 | 14 | input, 15 | button { 16 | font: inherit; 17 | } 18 | 19 | html { 20 | font-family: 'Poppins', sans-serif; 21 | } 22 | 23 | body { 24 | min-height: 100vh; 25 | background-color: #333; 26 | color: #fff; 27 | padding: 1rem; 28 | display: flex; 29 | flex-direction: column; 30 | } 31 | 32 | main { 33 | flex-grow: 1; 34 | margin: auto; 35 | width: 100%; 36 | max-width: 800px; 37 | display: flex; 38 | flex-flow: column nowrap; 39 | } 40 | 41 | section { 42 | border: 1px solid whitesmoke; 43 | border-radius: 10px; 44 | padding: 0.5rem; 45 | } 46 | 47 | .button { 48 | border-radius: 10px; 49 | min-width: 48px; 50 | min-height: 48px; 51 | } 52 | 53 | .button:hover { 54 | cursor: pointer; 55 | } 56 | 57 | .newItemEntry { 58 | position: sticky; 59 | top: 0; 60 | margin-bottom: 1rem; 61 | } 62 | 63 | .newItemEntry__form { 64 | display: flex; 65 | gap: 0.25rem; 66 | font-size: 1.5rem; 67 | } 68 | 69 | .newItemEntry__input { 70 | width: calc(100% - (0.25rem + 48px)); 71 | flex-grow: 1; 72 | border: 2px solid whitesmoke; 73 | border-radius: 10px; 74 | padding: 0.5em; 75 | } 76 | 77 | .newItemEntry__button { 78 | background-color: transparent; 79 | color: whitesmoke; 80 | border: 3px dashed whitesmoke; 81 | padding: 0.75em; 82 | } 83 | 84 | .newItemEntry__button:hover, 85 | .newItemEntry__button:focus { 86 | color: limegreen; 87 | } 88 | 89 | .listContainer { 90 | font-size: 1.5rem; 91 | flex-grow: 1; 92 | display: flex; 93 | flex-flow: column; 94 | gap: 1rem; 95 | } 96 | 97 | .listTitle { 98 | display: flex; 99 | justify-content: space-between; 100 | align-items: flex-end; 101 | } 102 | 103 | .listTitle__button { 104 | background-color: transparent; 105 | color: whitesmoke; 106 | padding: 0.25em; 107 | } 108 | 109 | 110 | .listItems { 111 | flex-grow: 1; 112 | display: flex; 113 | flex-flow: column nowrap; 114 | list-style-type: none; 115 | } 116 | 117 | .item { 118 | display: flex; 119 | align-items: center; 120 | padding-top: 1em; 121 | gap: 1em; 122 | } 123 | 124 | .item > input[type="checkbox"] { 125 | text-align: center; 126 | min-width: 2.5rem; 127 | min-height: 2.5rem; 128 | cursor: pointer; 129 | } 130 | 131 | .item > input[type="checkbox"]:checked + label { 132 | text-decoration: line-through; 133 | } 134 | 135 | .item > label { 136 | flex-grow: 1; 137 | word-break: break-all; 138 | } 139 | 140 | .item > button:hover, 141 | .item > button:focus { 142 | color: red; 143 | } 144 | 145 | @media (min-width: 768px) { 146 | section { 147 | padding: 1rem; 148 | } 149 | .newItemEntry__form { 150 | gap: 0.5rem; 151 | } 152 | } -------------------------------------------------------------------------------- /lesson11/src/main.ts: -------------------------------------------------------------------------------- 1 | import './css/style.css' 2 | import FullList from './model/FullList' 3 | import ListItem from './model/ListItem' 4 | import ListTemplate from './templates/ListTemplate' 5 | 6 | const initApp = (): void => { 7 | const fullList = FullList.instance 8 | const template = ListTemplate.instance 9 | 10 | // Add listener to new entry form submit 11 | const itemEntryForm = document.getElementById("itemEntryForm") as HTMLFormElement 12 | 13 | itemEntryForm.addEventListener("submit", (event: SubmitEvent): void => { 14 | event.preventDefault() 15 | 16 | // Get the new item value 17 | const input = document.getElementById("newItem") as HTMLInputElement 18 | const newEntryText: string = input.value.trim() 19 | if (!newEntryText.length) return 20 | 21 | // calculate item ID 22 | const itemId: number = fullList.list.length 23 | ? parseInt(fullList.list[fullList.list.length - 1].id) + 1 24 | : 1 25 | 26 | // create new item 27 | const newItem = new ListItem(itemId.toString(), newEntryText) 28 | // Add new item to full list 29 | fullList.addItem(newItem) 30 | // Re-render list with new item included 31 | template.render(fullList) 32 | }) 33 | 34 | // Add listener to "Clear" button 35 | const clearItems = document.getElementById("clearItemsButton") as HTMLButtonElement 36 | 37 | clearItems.addEventListener('click', (): void => { 38 | fullList.clearList() 39 | template.clear() 40 | }) 41 | 42 | // load initial data 43 | fullList.load() 44 | // initial render of template 45 | template.render(fullList) 46 | } 47 | 48 | document.addEventListener("DOMContentLoaded", initApp) -------------------------------------------------------------------------------- /lesson11/src/model/FullList.ts: -------------------------------------------------------------------------------- 1 | import ListItem from './ListItem' 2 | 3 | interface List { 4 | list: ListItem[], 5 | load(): void, 6 | save(): void, 7 | clearList(): void, 8 | addItem(itemObj: ListItem): void, 9 | removeItem(id: string): void, 10 | } 11 | 12 | export default class FullList implements List { 13 | 14 | static instance: FullList = new FullList() 15 | 16 | private constructor(private _list: ListItem[] = []) { } 17 | 18 | get list(): ListItem[] { 19 | return this._list 20 | } 21 | 22 | load(): void { 23 | const storedList: string | null = localStorage.getItem("myList") 24 | if (typeof storedList !== "string") return 25 | 26 | const parsedList: { _id: string, _item: string, _checked: boolean }[] = JSON.parse(storedList) 27 | 28 | parsedList.forEach(itemObj => { 29 | const newListItem = new ListItem(itemObj._id, itemObj._item, itemObj._checked) 30 | FullList.instance.addItem(newListItem) 31 | }) 32 | } 33 | 34 | save(): void { 35 | localStorage.setItem("myList", JSON.stringify(this._list)) 36 | } 37 | 38 | clearList(): void { 39 | this._list = [] 40 | this.save() 41 | } 42 | 43 | addItem(itemObj: ListItem): void { 44 | this._list.push(itemObj) 45 | this.save() 46 | } 47 | 48 | removeItem(id: string): void { 49 | this._list = this._list.filter(item => item.id !== id) 50 | this.save() 51 | } 52 | } -------------------------------------------------------------------------------- /lesson11/src/model/ListItem.ts: -------------------------------------------------------------------------------- 1 | export interface Item { 2 | id: string, 3 | item: string, 4 | checked: boolean, 5 | } 6 | 7 | export default class ListItem implements Item { 8 | 9 | constructor( 10 | private _id: string = '', 11 | private _item: string = '', 12 | private _checked: boolean = false, 13 | ) { } 14 | 15 | get id(): string { 16 | return this._id 17 | } 18 | 19 | set id(id: string) { 20 | this._id = id 21 | } 22 | 23 | get item(): string { 24 | return this._item 25 | } 26 | 27 | set item(item: string) { 28 | this._item = item 29 | } 30 | 31 | get checked(): boolean { 32 | return this._checked 33 | } 34 | 35 | set checked(checked: boolean) { 36 | this._checked = checked 37 | } 38 | } -------------------------------------------------------------------------------- /lesson11/src/templates/ListTemplate.ts: -------------------------------------------------------------------------------- 1 | import FullList from "../model/FullList" 2 | 3 | interface DOMList { 4 | ul: HTMLUListElement, 5 | clear(): void, 6 | render(fullList: FullList): void, 7 | } 8 | 9 | export default class ListTemplate implements DOMList { 10 | 11 | ul: HTMLUListElement 12 | 13 | static instance: ListTemplate = new ListTemplate() 14 | 15 | private constructor() { 16 | this.ul = document.getElementById("listItems") as HTMLUListElement 17 | } 18 | 19 | clear(): void { 20 | this.ul.innerHTML = '' 21 | } 22 | 23 | render(fullList: FullList): void { 24 | this.clear() 25 | 26 | fullList.list.forEach(item => { 27 | const li = document.createElement("li") as HTMLLIElement 28 | li.className = "item" 29 | 30 | const check = document.createElement("input") as HTMLInputElement 31 | check.type = "checkbox" 32 | check.id = item.id 33 | check.checked = item.checked 34 | li.append(check) 35 | 36 | check.addEventListener('change', () => { 37 | item.checked = !item.checked 38 | fullList.save() 39 | }) 40 | 41 | const label = document.createElement("label") as HTMLLabelElement 42 | label.htmlFor = item.id 43 | label.textContent = item.item 44 | li.append(label) 45 | 46 | const button = document.createElement("button") as HTMLButtonElement 47 | button.className = 'button' 48 | button.textContent = 'X' 49 | li.append(button) 50 | 51 | button.addEventListener('click', () => { 52 | fullList.removeItem(item.id) 53 | this.render(fullList) 54 | }) 55 | 56 | this.ul.append(li) 57 | }) 58 | } 59 | } -------------------------------------------------------------------------------- /lesson11/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /lesson11/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /lesson12/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lesson12/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lesson12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lesson12", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "^18.0.24", 17 | "@types/react-dom": "^18.0.8", 18 | "@vitejs/plugin-react": "^2.2.0", 19 | "typescript": "^4.6.4", 20 | "vite": "^3.2.3" 21 | } 22 | } -------------------------------------------------------------------------------- /lesson12/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson12/src/App.tsx: -------------------------------------------------------------------------------- 1 | import Heading from "./components/Heading" 2 | import { Section } from "./components/Section" 3 | import Counter from "./components/Counter" 4 | import List from "./components/List" 5 | 6 | import { useState } from 'react' 7 | 8 | function App() { 9 | const [count, setCount] = useState(1) 10 | 11 | return ( 12 | <> 13 | 14 |
This is my Section.
15 | Count is {count} 16 | {item}} /> 17 | 18 | ) 19 | } 20 | 21 | export default App 22 | -------------------------------------------------------------------------------- /lesson12/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson12/src/components/Counter.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react' 2 | 3 | type CounterProps = { 4 | setCount: React.Dispatch>, 5 | children: ReactNode, 6 | } 7 | 8 | const Counter = ({ setCount, children }: CounterProps) => { 9 | 10 | return ( 11 | <> 12 |

{children}

13 | 14 | 15 | 16 | ) 17 | } 18 | export default Counter -------------------------------------------------------------------------------- /lesson12/src/components/Heading.tsx: -------------------------------------------------------------------------------- 1 | import { ReactElement } from "react" 2 | 3 | type HeadingProps = { title: string } 4 | 5 | const Heading = ({ title }: HeadingProps): ReactElement => { 6 | return

{title}

7 | } 8 | export default Heading -------------------------------------------------------------------------------- /lesson12/src/components/List.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react' 2 | 3 | interface ListProps { 4 | items: T[], 5 | render: (item: T) => ReactNode 6 | } 7 | 8 | const List = ({ items, render }: ListProps) => { 9 | return ( 10 |
    11 | {items.map((item, i) => ( 12 |
  • 13 | {render(item)} 14 |
  • 15 | ))} 16 |
17 | ) 18 | } 19 | export default List -------------------------------------------------------------------------------- /lesson12/src/components/Section.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react" 2 | 3 | type SectionProps = { 4 | title?: string, 5 | children: ReactNode 6 | } 7 | 8 | export const Section = ({ children, title = "My Subheading" }: SectionProps) => { 9 | return ( 10 |
11 |

{title}

12 |

{children}

13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /lesson12/src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0.25rem; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-color: #333; 9 | color: whitesmoke; 10 | display: grid; 11 | place-content: center; 12 | font-size: 150%; 13 | } 14 | 15 | button { 16 | font-size: 2rem; 17 | } 18 | 19 | .bold { 20 | font-weight: bold; 21 | } 22 | 23 | .gold { 24 | color: gold; 25 | } -------------------------------------------------------------------------------- /lesson12/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /lesson12/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /lesson12/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /lesson12/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /lesson12/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()] 7 | }) 8 | -------------------------------------------------------------------------------- /lesson13/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lesson13/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lesson13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lesson13", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "^18.0.24", 17 | "@types/react-dom": "^18.0.8", 18 | "@vitejs/plugin-react": "^2.2.0", 19 | "typescript": "^4.6.4", 20 | "vite": "^3.2.3" 21 | } 22 | } -------------------------------------------------------------------------------- /lesson13/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson13/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback, useMemo, useRef, MouseEvent, KeyboardEvent } from 'react' 2 | 3 | interface User { 4 | id: number, 5 | username: string, 6 | } 7 | 8 | type fibFunc = (n: number) => number 9 | 10 | const fib: fibFunc = (n) => { 11 | if (n < 2) return n 12 | return fib(n - 1) + fib(n - 2) 13 | } 14 | 15 | const myNum: number = 37 16 | 17 | function App() { 18 | const [count, setCount] = useState(0) 19 | const [users, setUsers] = useState(null) 20 | 21 | const inputRef = useRef(null) 22 | 23 | console.log(inputRef?.current) 24 | console.log(inputRef?.current?.value) 25 | 26 | useEffect(() => { 27 | console.log('mounting') 28 | console.log('Users: ', users) 29 | 30 | return () => console.log('unmounting') 31 | }, [users]) 32 | 33 | const addTwo = useCallback((e: MouseEvent | KeyboardEvent): void => setCount(prev => prev + 2),[]) 34 | 35 | const result = useMemo(() => fib(myNum),[myNum]) 36 | 37 | return ( 38 |
39 |

{count}

40 | 41 |

{result}

42 | 43 |
44 | ) 45 | } 46 | 47 | export default App 48 | -------------------------------------------------------------------------------- /lesson13/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson13/src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0.25rem; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-color: #333; 9 | color: whitesmoke; 10 | display: grid; 11 | place-content: center; 12 | font-size: 150%; 13 | } 14 | 15 | button { 16 | font-size: 2rem; 17 | } 18 | 19 | .bold { 20 | font-weight: bold; 21 | } 22 | 23 | .gold { 24 | color: gold; 25 | } -------------------------------------------------------------------------------- /lesson13/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /lesson13/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /lesson13/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /lesson13/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /lesson13/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()] 7 | }) 8 | -------------------------------------------------------------------------------- /lesson14/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lesson14/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lesson14/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lesson14", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "^18.0.26", 17 | "@types/react-dom": "^18.0.9", 18 | "@vitejs/plugin-react": "^3.0.0", 19 | "typescript": "^4.9.3", 20 | "vite": "^4.0.0" 21 | } 22 | } -------------------------------------------------------------------------------- /lesson14/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson14/src/App.tsx: -------------------------------------------------------------------------------- 1 | import Counter from "./Counter" 2 | 3 | function App() { 4 | 5 | return ( 6 | <> 7 | {(num: number) => <>Current Count: {num}} 8 | 9 | ) 10 | } 11 | 12 | export default App 13 | -------------------------------------------------------------------------------- /lesson14/src/Counter.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useReducer, ChangeEvent } from 'react' 2 | 3 | const initState = { count: 0, text: '' } 4 | 5 | const enum REDUCER_ACTION_TYPE { 6 | INCREMENT, 7 | DECREMENT, 8 | NEW_INPUT, 9 | } 10 | 11 | type ReducerAction = { 12 | type: REDUCER_ACTION_TYPE, 13 | payload?: string, 14 | } 15 | 16 | const reducer = (state: typeof initState, action: ReducerAction): typeof initState => { 17 | switch (action.type) { 18 | case REDUCER_ACTION_TYPE.INCREMENT: 19 | return { ...state, count: state.count + 1 } 20 | case REDUCER_ACTION_TYPE.DECREMENT: 21 | return { ...state, count: state.count - 1 } 22 | case REDUCER_ACTION_TYPE.NEW_INPUT: 23 | return { ...state, text: action.payload ?? '' } 24 | default: 25 | throw new Error() 26 | } 27 | } 28 | 29 | type ChildrenType = { 30 | children: (num: number) => ReactNode 31 | } 32 | 33 | const Counter = ({ children }: ChildrenType) => { 34 | const [state, dispatch] = useReducer(reducer, initState) 35 | 36 | const increment = () => dispatch({ type: REDUCER_ACTION_TYPE.INCREMENT }) 37 | const decrement = () => dispatch({ type: REDUCER_ACTION_TYPE.DECREMENT }) 38 | const handleTextInput = (e: ChangeEvent) => { 39 | dispatch({ 40 | type: REDUCER_ACTION_TYPE.NEW_INPUT, 41 | payload: e.target.value 42 | }) 43 | } 44 | 45 | return ( 46 | <> 47 |

{children(state.count)}

48 |
49 | 50 | 51 |
52 | 53 |

{state.text}

54 | 55 | ) 56 | } 57 | export default Counter -------------------------------------------------------------------------------- /lesson14/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson14/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color-scheme: light dark; 8 | color: rgba(255, 255, 255, 0.87); 9 | background-color: #242424; 10 | 11 | font-synthesis: none; 12 | text-rendering: optimizeLegibility; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | -webkit-text-size-adjust: 100%; 16 | } 17 | 18 | a { 19 | font-weight: 500; 20 | color: #646cff; 21 | text-decoration: inherit; 22 | } 23 | a:hover { 24 | color: #535bf2; 25 | } 26 | 27 | body { 28 | margin: auto; 29 | min-width: 100%; 30 | min-height: 100vh; 31 | } 32 | 33 | #root { 34 | display: flex; 35 | flex-flow: column; 36 | justify-content: center; 37 | align-items: center; 38 | } 39 | 40 | h1 { 41 | font-size: 3.2em; 42 | line-height: 1.1; 43 | } 44 | 45 | button { 46 | margin: 0.25em; 47 | border-radius: 8px; 48 | border: 1px solid transparent; 49 | padding: 0.6em 1.2em; 50 | font-size: 1em; 51 | font-weight: 500; 52 | font-family: inherit; 53 | background-color: #1a1a1a; 54 | cursor: pointer; 55 | transition: border-color 0.25s; 56 | } 57 | button:hover { 58 | border-color: #646cff; 59 | } 60 | button:focus, 61 | button:focus-visible { 62 | outline: 4px auto -webkit-focus-ring-color; 63 | } 64 | 65 | @media (prefers-color-scheme: light) { 66 | :root { 67 | color: #213547; 68 | background-color: #ffffff; 69 | } 70 | a:hover { 71 | color: #747bff; 72 | } 73 | button { 74 | background-color: #f9f9f9; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lesson14/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /lesson14/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /lesson14/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /lesson14/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /lesson14/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /lesson15/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lesson15/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lesson15/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lesson14", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "^18.0.26", 17 | "@types/react-dom": "^18.0.9", 18 | "@vitejs/plugin-react": "^3.0.0", 19 | "typescript": "^4.9.3", 20 | "vite": "^4.0.0" 21 | } 22 | } -------------------------------------------------------------------------------- /lesson15/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson15/src/App.tsx: -------------------------------------------------------------------------------- 1 | import Counter from "./Counter" 2 | import { CounterProvider } from "./context/CounterContext" 3 | 4 | function App() { 5 | 6 | return ( 7 | <> 8 | 9 | {(num: number) => <>Current Count: {num}} 10 | 11 | 12 | ) 13 | } 14 | 15 | export default App 16 | -------------------------------------------------------------------------------- /lesson15/src/Counter.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react' 2 | import { useCounter } from './context/CounterContext' 3 | import { useCounterText } from './context/CounterContext' 4 | 5 | type ChildrenType = { 6 | children: (num: number) => ReactNode 7 | } 8 | 9 | const Counter = ({ children }: ChildrenType) => { 10 | const { count, increment, decrement } = useCounter() 11 | const { text, handleTextInput } = useCounterText() 12 | 13 | return ( 14 | <> 15 |

{children(count)}

16 |
17 | 18 | 19 |
20 | 21 |

{text}

22 | 23 | ) 24 | } 25 | export default Counter -------------------------------------------------------------------------------- /lesson15/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson15/src/context/CounterContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useReducer, ChangeEvent, ReactElement, useCallback, useContext } from "react" 2 | 3 | type StateType = { 4 | count: number; 5 | text: string; 6 | } 7 | 8 | const initState: StateType = { count: 0, text: '' } 9 | 10 | const enum REDUCER_ACTION_TYPE { 11 | INCREMENT, 12 | DECREMENT, 13 | NEW_INPUT, 14 | } 15 | 16 | type ReducerAction = { 17 | type: REDUCER_ACTION_TYPE, 18 | payload?: string, 19 | } 20 | 21 | const reducer = (state: StateType, action: ReducerAction): StateType => { 22 | switch (action.type) { 23 | case REDUCER_ACTION_TYPE.INCREMENT: 24 | return { ...state, count: state.count + 1 } 25 | case REDUCER_ACTION_TYPE.DECREMENT: 26 | return { ...state, count: state.count - 1 } 27 | case REDUCER_ACTION_TYPE.NEW_INPUT: 28 | return { ...state, text: action.payload ?? '' } 29 | default: 30 | throw new Error() 31 | } 32 | } 33 | 34 | const useCounterContext = (initState: StateType) => { 35 | const [state, dispatch] = useReducer(reducer, initState) 36 | 37 | const increment = useCallback(() => dispatch({ type: REDUCER_ACTION_TYPE.INCREMENT }), []) 38 | 39 | const decrement = useCallback(() => dispatch({ type: REDUCER_ACTION_TYPE.DECREMENT }), []) 40 | 41 | const handleTextInput = useCallback((e: ChangeEvent) => { 42 | dispatch({ 43 | type: REDUCER_ACTION_TYPE.NEW_INPUT, 44 | payload: e.target.value 45 | }) 46 | }, []) 47 | 48 | return { state, increment, decrement, handleTextInput } 49 | } 50 | 51 | type UseCounterContextType = ReturnType 52 | 53 | const initContextState: UseCounterContextType = { 54 | state: initState, 55 | increment: () => { }, 56 | decrement: () => { }, 57 | handleTextInput: (e: ChangeEvent) => { }, 58 | } 59 | 60 | export const CounterContext = createContext(initContextState) 61 | 62 | type ChildrenType = { 63 | children?: ReactElement | ReactElement[] | undefined 64 | } 65 | 66 | export const CounterProvider = ({ 67 | children 68 | }: ChildrenType): ReactElement => { 69 | return ( 70 | 71 | {children} 72 | 73 | ) 74 | } 75 | 76 | type UseCounterHookType = { 77 | count: number, 78 | increment: () => void, 79 | decrement: () => void, 80 | } 81 | 82 | export const useCounter = (): UseCounterHookType => { 83 | const { state: { count }, increment, decrement } = useContext(CounterContext) 84 | return { count, increment, decrement } 85 | } 86 | 87 | type UseCounterTextHookType = { 88 | text: string, 89 | handleTextInput: (e: ChangeEvent) => void, 90 | } 91 | 92 | export const useCounterText = (): UseCounterTextHookType => { 93 | const { state: { text }, handleTextInput } = useContext(CounterContext) 94 | return { text, handleTextInput } 95 | } -------------------------------------------------------------------------------- /lesson15/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color-scheme: light dark; 8 | color: rgba(255, 255, 255, 0.87); 9 | background-color: #242424; 10 | 11 | font-synthesis: none; 12 | text-rendering: optimizeLegibility; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | -webkit-text-size-adjust: 100%; 16 | } 17 | 18 | a { 19 | font-weight: 500; 20 | color: #646cff; 21 | text-decoration: inherit; 22 | } 23 | a:hover { 24 | color: #535bf2; 25 | } 26 | 27 | body { 28 | margin: auto; 29 | min-width: 100%; 30 | min-height: 100vh; 31 | } 32 | 33 | #root { 34 | display: flex; 35 | flex-flow: column; 36 | justify-content: center; 37 | align-items: center; 38 | } 39 | 40 | h1 { 41 | font-size: 3.2em; 42 | line-height: 1.1; 43 | } 44 | 45 | button { 46 | margin: 0.25em; 47 | border-radius: 8px; 48 | border: 1px solid transparent; 49 | padding: 0.6em 1.2em; 50 | font-size: 1em; 51 | font-weight: 500; 52 | font-family: inherit; 53 | background-color: #1a1a1a; 54 | cursor: pointer; 55 | transition: border-color 0.25s; 56 | } 57 | button:hover { 58 | border-color: #646cff; 59 | } 60 | button:focus, 61 | button:focus-visible { 62 | outline: 4px auto -webkit-focus-ring-color; 63 | } 64 | 65 | @media (prefers-color-scheme: light) { 66 | :root { 67 | color: #213547; 68 | background-color: #ffffff; 69 | } 70 | a:hover { 71 | color: #747bff; 72 | } 73 | button { 74 | background-color: #f9f9f9; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lesson15/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /lesson15/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /lesson15/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /lesson15/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /lesson15/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /lesson16/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lesson16/data/products.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ 3 | { 4 | "sku": "item0001", 5 | "name": "Widget", 6 | "price": 9.99 7 | }, 8 | { 9 | "sku": "item0002", 10 | "name": "Premium Widget", 11 | "price": 19.99 12 | }, 13 | { 14 | "sku": "item0003", 15 | "name": "Deluxe Widget", 16 | "price": 29.99 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /lesson16/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lesson16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lesson16", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "^18.0.26", 17 | "@types/react-dom": "^18.0.9", 18 | "@vitejs/plugin-react": "^3.0.0", 19 | "typescript": "^4.9.3", 20 | "vite": "^4.0.0" 21 | } 22 | } -------------------------------------------------------------------------------- /lesson16/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson16/src/App.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | function App() { 4 | 5 | return ( 6 |
7 | 8 |
9 | ) 10 | } 11 | 12 | export default App 13 | -------------------------------------------------------------------------------- /lesson16/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson16/src/context/CartProvider.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo, useReducer, createContext, ReactElement } from "react" 2 | 3 | export type CartItemType = { 4 | sku: string, 5 | name: string, 6 | price: number, 7 | qty: number, 8 | } 9 | 10 | type CartStateType = { cart: CartItemType[] } 11 | 12 | const initCartState: CartStateType = { cart: [] } 13 | 14 | const REDUCER_ACTION_TYPE = { 15 | ADD: "ADD", 16 | REMOVE: "REMOVE", 17 | QUANTITY: "QUANTITY", 18 | SUBMIT: "SUBMIT", 19 | } 20 | 21 | export type ReducerActionType = typeof REDUCER_ACTION_TYPE 22 | 23 | export type ReducerAction = { 24 | type: string, 25 | payload?: CartItemType, 26 | } 27 | 28 | const reducer = (state: CartStateType, action: ReducerAction): CartStateType => { 29 | switch (action.type) { 30 | case REDUCER_ACTION_TYPE.ADD: { 31 | if (!action.payload) { 32 | throw new Error('action.payload missing in ADD action') 33 | } 34 | 35 | const { sku, name, price } = action.payload 36 | 37 | const filteredCart: CartItemType[] = state.cart.filter(item => item.sku !== sku) 38 | 39 | const itemExists: CartItemType | undefined = state.cart.find(item => item.sku === sku) 40 | 41 | const qty: number = itemExists ? itemExists.qty + 1 : 1 42 | 43 | return { ...state, cart: [...filteredCart, { sku, name, price, qty }] } 44 | } 45 | case REDUCER_ACTION_TYPE.REMOVE: { 46 | if (!action.payload) { 47 | throw new Error('action.payload missing in REMOVE action') 48 | } 49 | 50 | const { sku } = action.payload 51 | 52 | const filteredCart: CartItemType[] = state.cart.filter(item => item.sku !== sku) 53 | 54 | return { ...state, cart: [...filteredCart] } 55 | } 56 | case REDUCER_ACTION_TYPE.QUANTITY: { 57 | if (!action.payload) { 58 | throw new Error('action.payload missing in QUANTITY action') 59 | } 60 | 61 | const { sku, qty } = action.payload 62 | 63 | const itemExists: CartItemType | undefined = state.cart.find(item => item.sku === sku) 64 | 65 | if (!itemExists) { 66 | throw new Error('Item must exist in order to update quantity') 67 | } 68 | 69 | const updatedItem: CartItemType = { ...itemExists, qty } 70 | 71 | const filteredCart: CartItemType[] = state.cart.filter(item => item.sku !== sku) 72 | 73 | return { ...state, cart: [...filteredCart, updatedItem] } 74 | } 75 | case REDUCER_ACTION_TYPE.SUBMIT: { 76 | return { ...state, cart: [] } 77 | } 78 | default: 79 | throw new Error('Unidentified reducer action type') 80 | } 81 | } 82 | 83 | const useCartContext = (initCartState: CartStateType) => { 84 | const [state, dispatch] = useReducer(reducer, initCartState) 85 | 86 | const REDUCER_ACTIONS = useMemo(() => { 87 | return REDUCER_ACTION_TYPE 88 | }, []) 89 | 90 | const totalItems = state.cart.reduce((previousValue, cartItem) => { 91 | return previousValue + cartItem.qty 92 | }, 0) 93 | 94 | const totalPrice = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format( 95 | state.cart.reduce((previousValue, cartItem) => { 96 | return previousValue + (cartItem.qty * cartItem.price) 97 | }, 0) 98 | ) 99 | 100 | const cart = state.cart.sort((a, b) => { 101 | const itemA = Number(a.sku.slice(-4)) 102 | const itemB = Number(b.sku.slice(-4)) 103 | return itemA - itemB 104 | }) 105 | 106 | return { dispatch, REDUCER_ACTIONS, totalItems, totalPrice, cart } 107 | } 108 | 109 | export type UseCartContextType = ReturnType 110 | 111 | const initCartContextState: UseCartContextType = { 112 | dispatch: () => { }, 113 | REDUCER_ACTIONS: REDUCER_ACTION_TYPE, 114 | totalItems: 0, 115 | totalPrice: '', 116 | cart: [], 117 | } 118 | 119 | const CartContext = createContext(initCartContextState) 120 | 121 | type ChildrenType = { children?: ReactElement | ReactElement[] } 122 | 123 | export const CartProvider = ({ children }: ChildrenType): ReactElement => { 124 | return ( 125 | 126 | {children} 127 | 128 | ) 129 | } 130 | 131 | export default CartContext -------------------------------------------------------------------------------- /lesson16/src/context/ProductsProvider.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, ReactElement, useState, useEffect } from "react" 2 | 3 | export type ProductType = { 4 | sku: string, 5 | name: string, 6 | price: number, 7 | } 8 | 9 | const initState: ProductType[] = [] 10 | // const initState: ProductType[] = [ 11 | // { 12 | // "sku": "item0001", 13 | // "name": "Widget", 14 | // "price": 9.99 15 | // }, 16 | // { 17 | // "sku": "item0002", 18 | // "name": "Premium Widget", 19 | // "price": 19.99 20 | // }, 21 | // { 22 | // "sku": "item0003", 23 | // "name": "Deluxe Widget", 24 | // "price": 29.99 25 | // } 26 | // ] 27 | 28 | export type UseProductsContextType = { products: ProductType[] } 29 | 30 | const initContextState: UseProductsContextType = { products: [] } 31 | 32 | const ProductsContext = createContext(initContextState) 33 | 34 | type ChildrenType = { children?: ReactElement | ReactElement[] } 35 | 36 | export const ProductsProvider = ({ children }: ChildrenType): ReactElement => { 37 | const [products, setProducts] = useState(initState) 38 | 39 | useEffect(() => { 40 | const fetchProducts = async (): Promise => { 41 | const data = await fetch('http://localhost:3500/products').then(res => { 42 | return res.json() 43 | }).catch(err => { 44 | if (err instanceof Error) console.log(err.message) 45 | }) 46 | return data 47 | } 48 | 49 | fetchProducts().then(products => setProducts(products)) 50 | }, []) 51 | 52 | return ( 53 | 54 | {children} 55 | 56 | ) 57 | 58 | } 59 | 60 | export default ProductsContext -------------------------------------------------------------------------------- /lesson16/src/images/item0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/principlesoftware-dev/tutor-typescript/1d3f53073d47126ca510f78ea075cd8f67a42145/lesson16/src/images/item0001.jpg -------------------------------------------------------------------------------- /lesson16/src/images/item0002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/principlesoftware-dev/tutor-typescript/1d3f53073d47126ca510f78ea075cd8f67a42145/lesson16/src/images/item0002.jpg -------------------------------------------------------------------------------- /lesson16/src/images/item0003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/principlesoftware-dev/tutor-typescript/1d3f53073d47126ca510f78ea075cd8f67a42145/lesson16/src/images/item0003.jpg -------------------------------------------------------------------------------- /lesson16/src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Nunito&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | .offscreen { 10 | position: absolute; 11 | left: -10000px; 12 | } 13 | 14 | body { 15 | font-family: 'Nunito', sans-serif; 16 | } 17 | 18 | button, 19 | select { 20 | font: inherit; 21 | padding: 0.25em; 22 | } 23 | 24 | img { 25 | display: block; 26 | width: 100%; 27 | height: auto; 28 | border-radius: 10px; 29 | } 30 | 31 | #root { 32 | /* React root div */ 33 | min-height: 100vh; 34 | display: flex; 35 | flex-flow: column nowrap; 36 | } 37 | 38 | .main, 39 | .header, 40 | .footer { 41 | padding: 0.25em; 42 | margin: 0 1em; 43 | } 44 | 45 | .main { 46 | display: flex; 47 | gap: 1rem; 48 | } 49 | 50 | .main--products { 51 | flex-flow: row wrap; 52 | justify-content: space-between; 53 | } 54 | 55 | .main--cart { 56 | flex-flow: column nowrap; 57 | } 58 | 59 | .header { 60 | background-color: #fff; 61 | position: sticky; 62 | top: 0; 63 | z-index: 1; 64 | border-bottom: 1px solid #000; 65 | } 66 | 67 | .header__title-bar { 68 | display: flex; 69 | justify-content: space-between; 70 | margin-bottom: 0.5em; 71 | } 72 | 73 | .header__price-box { 74 | text-align: right; 75 | } 76 | 77 | .nav { 78 | display: flex; 79 | justify-content: flex-end; 80 | gap: 0.5em; 81 | } 82 | 83 | .footer { 84 | flex-grow: 1; 85 | display: flex; 86 | flex-flow: column nowrap; 87 | justify-content: flex-end; 88 | } 89 | 90 | .product { 91 | width: 90%; 92 | margin-bottom: 1em; 93 | } 94 | 95 | .product__img { 96 | max-width: 350px; 97 | } 98 | 99 | .cart { 100 | padding: 0; 101 | margin-top: 0.5em; 102 | } 103 | 104 | .cart__item { 105 | display: grid; 106 | grid-template-columns: 4fr 3fr 1fr 1fr; 107 | gap: 0.5rem; 108 | margin-bottom: 0.5em; 109 | } 110 | 111 | .cart__img { 112 | display: none; 113 | min-width: 68px; 114 | } 115 | 116 | .cart__select { 117 | max-height: 48px; 118 | } 119 | 120 | .cart__item-subtotal { 121 | display: none; 122 | text-align: center; 123 | } 124 | 125 | .cart__button { 126 | max-height: 48px; 127 | justify-self: flex-end; 128 | } 129 | 130 | .cart__totals { 131 | display: flex; 132 | flex-flow: column; 133 | gap: 1em; 134 | } 135 | 136 | @media screen and (min-width: 601px) { 137 | .product { 138 | width: 30%; 139 | } 140 | 141 | .cart__item { 142 | grid-template-columns: 3fr 15fr 5fr 1fr 8fr 1fr; 143 | } 144 | 145 | .cart__img, .cart__item-subtotal { 146 | display: block; 147 | } 148 | 149 | .cart__submit { 150 | max-width: 300px; 151 | } 152 | } -------------------------------------------------------------------------------- /lesson16/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /lesson16/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /lesson16/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /lesson16/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /lesson16/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /lesson17/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lesson17/data/products.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ 3 | { 4 | "sku": "item0001", 5 | "name": "Widget", 6 | "price": 9.99 7 | }, 8 | { 9 | "sku": "item0002", 10 | "name": "Premium Widget", 11 | "price": 19.99 12 | }, 13 | { 14 | "sku": "item0003", 15 | "name": "Deluxe Widget", 16 | "price": 29.99 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /lesson17/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lesson17/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lesson17", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "^18.0.26", 17 | "@types/react-dom": "^18.0.9", 18 | "@vitejs/plugin-react": "^3.0.0", 19 | "typescript": "^4.9.3", 20 | "vite": "^4.0.0" 21 | } 22 | } -------------------------------------------------------------------------------- /lesson17/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson17/src/App.tsx: -------------------------------------------------------------------------------- 1 | import Header from "./components/Header" 2 | import Footer from "./components/Footer" 3 | import Cart from "./components/Cart" 4 | import ProductList from "./components/ProductList" 5 | import { useState } from "react" 6 | 7 | function App() { 8 | const [viewCart, setViewCart] = useState(false) 9 | 10 | const pageContent = viewCart ? : 11 | 12 | const content = ( 13 | <> 14 |
15 | {pageContent} 16 |