├── .DS_Store ├── .gitignore ├── 000-ts-starter └── index.ts ├── 001-ts-compile-to-js ├── index.ts └── tsconfig.json ├── 002-ts-config ├── index.ts └── tsconfig.json ├── 003-ts-config-from-vite ├── .gitignore ├── README.md ├── index.html ├── package.json ├── public │ └── vite.svg ├── src │ ├── counter.ts │ ├── main.ts │ ├── style.css │ ├── typescript.svg │ └── vite-env.d.ts └── tsconfig.json ├── 004-type-annotation-and-inference └── index.ts ├── 005-js-core-types └── index.js ├── 006-ts-string-type └── index.ts ├── 007-ts-number-type └── index.ts ├── 008-ts-boolean-type └── index.ts ├── 009-ts-any-type └── index.ts ├── 010-ts-null-undefined └── index.ts ├── 011-ts-union-and-literal-type └── index.ts ├── 012-ts-unknown-type └── index.ts ├── 013-ts-never-type └── index.ts ├── 014-ts-enum-type └── index.ts ├── 015-ts-basic-object └── index.ts ├── 016-ts-object-optional-properties └── index.ts ├── 017-ts-array └── index.ts ├── 018-ts-type-keyword-aliases └── index.ts ├── 019-ts-tuple └── index.ts ├── 020-ts-function-type └── index.ts ├── 021-ts-function-void-type └── index.ts ├── 022-ts-function-overloads └── index.ts ├── 023-ts-intersection └── index.ts ├── 024-ts-intersection-incompatible └── index.ts ├── 025-ts-interface └── index.ts ├── 026-ts-interface-extend-version └── index.ts ├── 027-ts-interface-as-function └── index.ts ├── 028-ts-when-should-use-interface-vs-type └── index.ts ├── 029-ts-readonly └── index.ts ├── 030-ts-keyof └── index.ts ├── 031-ts-typeof └── index.ts ├── 032-ts-index-type └── index.ts ├── 033-ts-predefind-keys-by-default-with-index └── index.ts ├── 034-ts-union-keys-in-index └── index.ts ├── 035-ts-generic └── index.ts ├── 036-ts-async-function └── index.ts ├── 037-ts-Pick └── index.ts ├── 038-ts-Omit └── index.ts ├── 039-ts-Partial └── index.ts ├── 040-ts-Required └── index.ts ├── 041-ts-Record └── index.ts ├── 042-ts-Readonly └── index.ts ├── 043-ts-as-type-casting └── index.ts ├── 044-ts-satisfies └── index.ts ├── 045-ts-different-scope-narrowing └── index.ts ├── 046-ts-narrowing-with-discriminated-union └── index.ts ├── 047-ts-narrowing-with-discriminated-union-switch-statement └── index.ts ├── 048-ts-is-predicates-type-guard └── index.ts ├── 049-ts-assertion-predicates-type-guard └── index.ts ├── 050-ts-class └── index.ts ├── For-Ts-eBook.md ├── README.md └── tsconfig.json /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwinmoepaing/typescript-baby/b28705abdd327084960995529f2dae90337e2f1d/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.js 2 | 3 | **/node_modules 4 | 5 | **/package-lock.json 6 | 7 | !/005-js-core-types/index.js -------------------------------------------------------------------------------- /000-ts-starter/index.ts: -------------------------------------------------------------------------------- 1 | // npm i -g ts-node 2 | // npm i -g typescript 3 | 4 | console.log("Hello world!"); -------------------------------------------------------------------------------- /001-ts-compile-to-js/index.ts: -------------------------------------------------------------------------------- 1 | const myName: string = "LMP"; 2 | console.log(myName); 3 | -------------------------------------------------------------------------------- /001-ts-compile-to-js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "ES5", 5 | "module": "ESNext", 6 | }, 7 | "exclude": ["*.js"] 8 | } 9 | -------------------------------------------------------------------------------- /002-ts-config/index.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /002-ts-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ 40 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 41 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 42 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 43 | // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ 44 | // "resolveJsonModule": true, /* Enable importing .json files. */ 45 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 46 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 47 | 48 | /* JavaScript Support */ 49 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 50 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 51 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 52 | 53 | /* Emit */ 54 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 55 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 56 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 57 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "noEmit": true, /* Disable emitting files from a compilation. */ 60 | // "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. */ 61 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 62 | // "removeComments": true, /* Disable emitting comments. */ 63 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 64 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 65 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 66 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 67 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 68 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 69 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 70 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 71 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 72 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 73 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 74 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ 80 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 81 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 82 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 83 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 84 | 85 | /* Type Checking */ 86 | "strict": true, /* Enable all strict type-checking options. */ 87 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 88 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 89 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 90 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 91 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 92 | // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ 93 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 94 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 95 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 96 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 97 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 98 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 99 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 100 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 101 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 102 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 103 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 104 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 105 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 106 | 107 | /* Completeness */ 108 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 109 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/.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 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/README.md: -------------------------------------------------------------------------------- 1 | > npx 2 | > create-vite 3 | 4 | ✔ Project name: … . 5 | ✔ Select a framework: › Vanilla 6 | ✔ Select a variant: › TypeScript 7 | 8 | Scaffolding project in /003-ts-config-from-vite... 9 | 10 | Done. Now run: 11 | 12 | npm install 13 | npm run dev 14 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "003-ts-config-from-vite", 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": "~5.6.2", 13 | "vite": "^6.0.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/src/counter.ts: -------------------------------------------------------------------------------- 1 | export function setupCounter(element: HTMLButtonElement) { 2 | let counter = 0 3 | const setCounter = (count: number) => { 4 | counter = count 5 | element.innerHTML = `count is ${counter}` 6 | } 7 | element.addEventListener('click', () => setCounter(counter + 1)) 8 | setCounter(0) 9 | } 10 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/src/main.ts: -------------------------------------------------------------------------------- 1 | import './style.css' 2 | import typescriptLogo from './typescript.svg' 3 | import viteLogo from '/vite.svg' 4 | import { setupCounter } from './counter.ts' 5 | 6 | document.querySelector('#app')!.innerHTML = ` 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |

Vite + TypeScript

15 |
16 | 17 |
18 |

19 | Click on the Vite and TypeScript logos to learn more 20 |

21 |
22 | ` 23 | 24 | setupCounter(document.querySelector('#counter')!) 25 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | #app { 39 | max-width: 1280px; 40 | margin: 0 auto; 41 | padding: 2rem; 42 | text-align: center; 43 | } 44 | 45 | .logo { 46 | height: 6em; 47 | padding: 1.5em; 48 | will-change: filter; 49 | transition: filter 300ms; 50 | } 51 | .logo:hover { 52 | filter: drop-shadow(0 0 2em #646cffaa); 53 | } 54 | .logo.vanilla:hover { 55 | filter: drop-shadow(0 0 2em #3178c6aa); 56 | } 57 | 58 | .card { 59 | padding: 2em; 60 | } 61 | 62 | .read-the-docs { 63 | color: #888; 64 | } 65 | 66 | button { 67 | border-radius: 8px; 68 | border: 1px solid transparent; 69 | padding: 0.6em 1.2em; 70 | font-size: 1em; 71 | font-weight: 500; 72 | font-family: inherit; 73 | background-color: #1a1a1a; 74 | cursor: pointer; 75 | transition: border-color 0.25s; 76 | } 77 | button:hover { 78 | border-color: #646cff; 79 | } 80 | button:focus, 81 | button:focus-visible { 82 | outline: 4px auto -webkit-focus-ring-color; 83 | } 84 | 85 | @media (prefers-color-scheme: light) { 86 | :root { 87 | color: #213547; 88 | background-color: #ffffff; 89 | } 90 | a:hover { 91 | color: #747bff; 92 | } 93 | button { 94 | background-color: #f9f9f9; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/src/typescript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /003-ts-config-from-vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /004-type-annotation-and-inference/index.ts: -------------------------------------------------------------------------------- 1 | // Variable annotation 2 | 3 | let myName: string = "LMP"; 4 | console.log("myName = ", myName); 5 | 6 | let age: number = 28; 7 | console.log("age = ", age); 8 | 9 | let isStudent: boolean; 10 | isStudent = false; 11 | console.log("isStudent = ", isStudent); 12 | 13 | // Type inference 14 | 15 | let address = "YGN"; 16 | console.log("address = ", address); 17 | 18 | let x = 10; 19 | let y = 20; 20 | 21 | const add = (a: number, b: number) => { 22 | return a + b; 23 | }; 24 | 25 | console.log(add(x, y)); -------------------------------------------------------------------------------- /005-js-core-types/index.js: -------------------------------------------------------------------------------- 1 | console.log(typeof "Hello world!"); // string 2 | console.log(typeof 42); // number 3 | console.log(typeof true); // boolean 4 | console.log(typeof BigInt("145")); // bigint 5 | console.log(typeof Symbol("@")); // symbol 6 | console.log(typeof null); // null 7 | console.log(typeof undefined); // undefinded 8 | 9 | class Car { 10 | constructor(name) { 11 | this.name = name; 12 | } 13 | } 14 | 15 | const car = new Car("BMW"); 16 | console.log(typeof car); // Car Class 17 | 18 | console.log(typeof new Map()); // object 19 | console.log(typeof ["hello", "world"]); // object 20 | 21 | console.log(typeof function () {}); // function 22 | -------------------------------------------------------------------------------- /006-ts-string-type/index.ts: -------------------------------------------------------------------------------- 1 | let myName = "LMP"; 2 | console.log("myName = ", myName); -------------------------------------------------------------------------------- /007-ts-number-type/index.ts: -------------------------------------------------------------------------------- 1 | let year = 2024; 2 | console.log("year = ", year); 3 | -------------------------------------------------------------------------------- /008-ts-boolean-type/index.ts: -------------------------------------------------------------------------------- 1 | const isPerson = true; 2 | console.log(isPerson); 3 | -------------------------------------------------------------------------------- /009-ts-any-type/index.ts: -------------------------------------------------------------------------------- 1 | let anyValue; 2 | 3 | anyValue = "Lwin"; 4 | 5 | anyValue = 1; 6 | 7 | anyValue = [1, 2, 3]; 8 | 9 | // Constant Any 10 | let anyAnnotation: any = 123; 11 | 12 | anyAnnotation = "Something"; 13 | 14 | anyAnnotation.nothingMethod(); 15 | 16 | // Reality 17 | 18 | fetch("https://jsonplaceholder.typicode.com/users") 19 | .then((res) => res.json()) 20 | .then((json) => { 21 | // Any type 22 | console.log(json); 23 | }); 24 | -------------------------------------------------------------------------------- /010-ts-null-undefined/index.ts: -------------------------------------------------------------------------------- 1 | const nullData: null = null; 2 | 3 | console.log(nullData); 4 | 5 | let nullInfer = null; 6 | 7 | console.log(nullInfer); 8 | 9 | const undefindedData: undefined = undefined; 10 | 11 | console.log(undefindedData); 12 | 13 | let undeInfer = undefined; 14 | 15 | console.log(undeInfer); 16 | -------------------------------------------------------------------------------- /011-ts-union-and-literal-type/index.ts: -------------------------------------------------------------------------------- 1 | let numberOrStr: string | number = 1; 2 | numberOrStr = "LMP"; 3 | 4 | // Literal Type 5 | let orderStatus: "pending" | "ongoing" | "delivered" = "pending"; 6 | orderStatus = "delivered"; 7 | console.log(orderStatus); 8 | 9 | let categoryNo: 1 | 2 = 2; 10 | console.log(categoryNo); 11 | -------------------------------------------------------------------------------- /012-ts-unknown-type/index.ts: -------------------------------------------------------------------------------- 1 | const a: unknown = "string"; 2 | 3 | // Unlikey "any" type 4 | // We can't access object like a.someMethod(); 5 | // or a.someProperties 6 | console.log(a); 7 | 8 | // Mostly we can get unknown error 9 | const throwError = () => { 10 | throw new Error("Just throwing error message"); 11 | }; 12 | 13 | try { 14 | throwError(); 15 | } catch (error) { 16 | // error is unknown in catch 17 | 18 | if (error instanceof Error) { 19 | console.log(error.message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /013-ts-never-type/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | const data = { 3 | items: [], 4 | }; 5 | 6 | type ItemType = (typeof data)["items"]; 7 | 8 | console.log(data); 9 | 10 | // We can't assign below this because of 'never[]' type 11 | // data.items.push("JavaScript"); 12 | // data.items.push("TypeScript"); 13 | 14 | // Never Happen ---- Bottomest Level 15 | // getNever function will response never type 16 | const getNever = () => { 17 | throw new Error("For Unknown"); 18 | }; 19 | 20 | const name: string = getNever(); 21 | const age: number = getNever(); 22 | -------------------------------------------------------------------------------- /014-ts-enum-type/index.ts: -------------------------------------------------------------------------------- 1 | enum Role { 2 | USER, 3 | SUPERVISOR, 4 | ADMIN, 5 | SUPERADMIN, 6 | } 7 | 8 | const userRole: Role = Role.USER; 9 | console.log(userRole); 10 | 11 | enum Permission { 12 | CREATE = "CREATE", 13 | READ = "READ", 14 | UPDATE = "UPDATE", 15 | DELETE = "DELETE", 16 | } 17 | 18 | const readPermission = Permission.READ; 19 | console.log(readPermission); 20 | -------------------------------------------------------------------------------- /015-ts-basic-object/index.ts: -------------------------------------------------------------------------------- 1 | // Inference 2 | const personInfer = { 3 | name: "LMP", 4 | location: "CNX", 5 | status: "active", 6 | }; 7 | console.log(personInfer.location); 8 | 9 | // Basic Object 10 | const person: { 11 | name: string; 12 | age: number; 13 | status: "active" | "inactive"; 14 | } = { 15 | name: "Lwin", 16 | age: 28, 17 | status: "active", 18 | }; 19 | console.log(person.name); 20 | console.log(person.status); 21 | -------------------------------------------------------------------------------- /016-ts-object-optional-properties/index.ts: -------------------------------------------------------------------------------- 1 | // Optional Properties "?:" 2 | let person: { 3 | name: string; 4 | status?: "active" | "inactive"; 5 | } = { 6 | name: "LMP", 7 | }; 8 | 9 | person.status = "inactive"; 10 | 11 | console.log(person); 12 | -------------------------------------------------------------------------------- /017-ts-array/index.ts: -------------------------------------------------------------------------------- 1 | const normalStr: string = "Hello World"; 2 | 3 | const strArray: string[] = ["Hello", "World", "!!"]; 4 | 5 | const nextStrArr: Array = ["Hello"]; 6 | 7 | const noArray: number[] = [1, 2, 3]; 8 | 9 | const nextNoArray: Array = [1, 2, 3]; 10 | 11 | let factorialNo: number[] = []; 12 | factorialNo = [1, 1, 2, 6, 24]; 13 | 14 | const primeNo: number[] = []; 15 | primeNo.push(2, 3, 5, 7, 11); 16 | 17 | const nested: string[][] = [ 18 | ["Hello", "-"], 19 | ["new", "World"], 20 | ["Lorem........."], 21 | ]; 22 | 23 | const newNested: Array = [ 24 | ["Hello", "-"], 25 | ["new", "World"], 26 | ["Lorem........."], 27 | ]; 28 | -------------------------------------------------------------------------------- /018-ts-type-keyword-aliases/index.ts: -------------------------------------------------------------------------------- 1 | type Person = { 2 | name: string; 3 | age: number; 4 | status: "active" | "inactive"; 5 | }; 6 | 7 | // Basic Object 8 | const person: Person = { 9 | name: "Lwin", 10 | age: 28, 11 | status: "active", 12 | }; 13 | console.log(person.name); 14 | console.log(person.status); 15 | -------------------------------------------------------------------------------- /019-ts-tuple/index.ts: -------------------------------------------------------------------------------- 1 | // Tuple 2 | // Example Color Tutple [Red, Green, Blue] 3 | type ColorTuple = [number, number, number]; 4 | 5 | const red: ColorTuple = [255, 0, 0]; 6 | console.log(red); 7 | 8 | // Listing for custom Tuple 9 | // Sometime we are using as Matrix !! 10 | const colorList: ColorTuple[] = [ 11 | [1, 0, 0], 12 | [0, 1, 0], 13 | [0, 0, 1], 14 | ]; 15 | console.log(colorList); 16 | 17 | // Key Value Tuple Array 18 | // Want to get tuple-list from this object {"name": "LMP", "location": "CNX"} 19 | // Response: [ ["name", "LMP"], ["location": "CNX"] ] 20 | 21 | type PersonTuple = [string, string]; // [key, value] 22 | const person = { name: "LMP", location: "CNX" }; 23 | 24 | let personTupleList: PersonTuple[] = []; 25 | 26 | Object.keys(person).map((key) => { 27 | // We'll learn later "typeof" & "keyof" & "as" 28 | type keys = keyof typeof person; 29 | const personKey = key as keys; 30 | 31 | personTupleList.push([personKey, person[personKey]]); 32 | }); 33 | 34 | console.log(personTupleList); 35 | -------------------------------------------------------------------------------- /020-ts-function-type/index.ts: -------------------------------------------------------------------------------- 1 | // Auto Recognized - Return Type 2 | function sumFn(a: number, b: number) { 3 | return a + b; 4 | } 5 | console.log(sumFn(1, 2)); 6 | 7 | // Defined Return Type 8 | function sumFnTwo(a: number, b: number): number { 9 | return a + b; 10 | } 11 | console.log(sumFnTwo(1, 2)); 12 | 13 | // Auto Recognized - Assigned Type 14 | const addFn = (a: number, b: number) => { 15 | return a + b; 16 | }; 17 | console.log(addFn(1, 2)); 18 | 19 | // Defined Return Type 20 | type SumType = (a: number, b: number) => number; 21 | const addFnTwo: SumType = (a: number, b: number) => { 22 | return a + b; 23 | }; 24 | 25 | console.log(addFnTwo(1, 2)); 26 | -------------------------------------------------------------------------------- /021-ts-function-void-type/index.ts: -------------------------------------------------------------------------------- 1 | function print(message: string) { 2 | console.log(message); 3 | } 4 | 5 | const helloMessage = print("Hello"); 6 | 7 | // helloMessage is void type 8 | 9 | function getName(callback: (name: string) => void) { 10 | const defaultName = "Default Name"; 11 | callback(defaultName); 12 | } 13 | 14 | getName((name) => { 15 | console.log(name); 16 | }); 17 | -------------------------------------------------------------------------------- /022-ts-function-overloads/index.ts: -------------------------------------------------------------------------------- 1 | type ResponseType = { 2 | success: boolean; 3 | data: number; 4 | }; 5 | 6 | const successResponse = (data: number): ResponseType => ({ 7 | success: true, 8 | data, 9 | }); 10 | 11 | function sum(x: number[]): number; 12 | function sum(x: number[], standardResponse: true): ResponseType; 13 | function sum(x: number, y: number): number; 14 | function sum(x: number, y: number, standardResponse: true): ResponseType; 15 | function sum( 16 | numberOrArray: number[] | number, 17 | numberOrStandardRes: number | true = 0, 18 | standardResponse?: true 19 | ) { 20 | // When First Parameter is Number Array 21 | const isArray = Array.isArray(numberOrArray); 22 | 23 | if (isArray) { 24 | const numberArray = numberOrArray; 25 | const standardResponse = numberOrStandardRes; 26 | const totalSum = numberArray.reduce((acc, next) => acc + next, 0); 27 | return standardResponse ? successResponse(totalSum) : totalSum; 28 | } 29 | 30 | // When First Parameter is number 31 | const x = numberOrArray; 32 | const y = numberOrStandardRes; 33 | if (typeof y === "boolean") { 34 | throw Error( 35 | "When First Parameter is Number, Second Parameter must be Number" 36 | ); 37 | } 38 | 39 | const totalSum = x + y; 40 | return standardResponse ? successResponse(totalSum) : totalSum; 41 | } 42 | 43 | const totalA = sum(1, 2); 44 | // result: 3 45 | 46 | const totalB = sum([4, 6]); 47 | // result: 10 48 | -------------------------------------------------------------------------------- /023-ts-intersection/index.ts: -------------------------------------------------------------------------------- 1 | type People = { 2 | name: string; 3 | age: number; 4 | }; 5 | 6 | type Role = { 7 | role: "admin" | "user"; 8 | }; 9 | 10 | type Admin = People & Role; 11 | 12 | const admin: Admin = { 13 | name: "LMP", 14 | age: 20, 15 | role: "admin", 16 | }; 17 | 18 | console.log(admin); 19 | -------------------------------------------------------------------------------- /024-ts-intersection-incompatible/index.ts: -------------------------------------------------------------------------------- 1 | type BasedUser = { 2 | id: string; 3 | }; 4 | 5 | type Person = { 6 | id: number; 7 | name: string; 8 | }; 9 | 10 | type Admin = BasedUser & Person; 11 | 12 | // const admin: Admin = { 13 | // id: "admin", 14 | // name: "Admin", 15 | // }; 16 | // console.log(admin); 17 | 18 | -------------------------------------------------------------------------------- /025-ts-interface/index.ts: -------------------------------------------------------------------------------- 1 | // Example: Basic `interface` 2 | interface User { 3 | id: string; // Required property 4 | name: string; // Required property 5 | age?: number; // Optional property (denoted by `?`) 6 | } 7 | 8 | const user: User = { 9 | id: "123", 10 | name: "John", 11 | // `age` is optional, so this is still valid: 12 | }; 13 | 14 | // Invalid object: 15 | // ❌ Error: Property 'name' is missing. 16 | const invalidUser: User = { 17 | id: "123", 18 | }; 19 | 20 | // Example: Adding Methods to an Interface 21 | interface UserWithMethods { 22 | id: string; 23 | name: string; 24 | greet(): string; // Method definition 25 | } 26 | 27 | const userWithMethods: UserWithMethods = { 28 | id: "456", 29 | name: "Alice", 30 | greet() { 31 | return `Hello, my name is ${this.name}!`; 32 | }, 33 | }; -------------------------------------------------------------------------------- /026-ts-interface-extend-version/index.ts: -------------------------------------------------------------------------------- 1 | // Example: Extending a Single Interface 2 | interface Person { 3 | name: string; 4 | age: number; 5 | } 6 | 7 | interface Employee extends Person { 8 | role: string; // New property added 9 | } 10 | 11 | const employee: Employee = { 12 | name: "Alice", 13 | age: 30, 14 | role: "Developer", // `role` comes from the `Employee` interface 15 | }; 16 | 17 | // Example: Extending Multiple Interfaces 18 | interface Contact { 19 | email: string; 20 | phone: string; 21 | } 22 | 23 | interface Manager extends Person, Contact { 24 | department: string; 25 | } 26 | 27 | const manager: Manager = { 28 | name: "Bob", 29 | age: 40, 30 | email: "bob@example.com", 31 | phone: "123-456-7890", 32 | department: "Engineering", 33 | }; 34 | 35 | // Real-world Example: Reusing Common Structures 36 | interface BaseResponse { 37 | status: number; 38 | message: string; 39 | } 40 | 41 | interface SuccessResponse extends BaseResponse { 42 | data: object; 43 | } 44 | 45 | interface ErrorResponse extends BaseResponse { 46 | errorCode: string; 47 | } 48 | 49 | const success: SuccessResponse = { 50 | status: 200, 51 | message: "Request succeeded", 52 | data: { id: 1, name: "John" }, 53 | }; 54 | 55 | const error: ErrorResponse = { 56 | status: 404, 57 | message: "Not Found", 58 | errorCode: "RESOURCE_NOT_FOUND", 59 | }; 60 | -------------------------------------------------------------------------------- /027-ts-interface-as-function/index.ts: -------------------------------------------------------------------------------- 1 | // Interface As The Function 2 | 3 | // Example 1: Print Function - Logs a string (Return Type: void) 4 | interface PrintFn { 5 | (str: string): void; 6 | } 7 | 8 | const print: PrintFn = (log) => { 9 | console.log(log); 10 | }; 11 | 12 | print("Hello World"); 13 | 14 | // Example 2: Sum Function - Adds two numbers (Return Type: number) 15 | interface Sum { 16 | (a: number, b: number): number; 17 | } 18 | 19 | const add: Sum = (a, b) => a + b; 20 | console.log(add(10, 20)); // 30 21 | 22 | // Example 3: Fetch Data Function - Mimics an API call (Return Type: Promise) 23 | interface FetchData { 24 | (url: string): Promise; 25 | } 26 | 27 | const fetchData: FetchData = async (url) => { 28 | // Simulating an API call 29 | return new Promise((resolve) => { 30 | setTimeout(() => resolve(`Data from ${url}`), 1000); 31 | }); 32 | }; 33 | fetchData("https://api.example.com/data").then(console.log); 34 | 35 | // Example 4: String Formatter - Capitalizes a string 36 | interface StringFormatter { 37 | (input: string): string; 38 | } 39 | 40 | const capitalize: StringFormatter = (input) => 41 | input.charAt(0).toUpperCase() + input.slice(1).toLowerCase(); 42 | console.log(capitalize("hello world")); // Hello world -------------------------------------------------------------------------------- /028-ts-when-should-use-interface-vs-type/index.ts: -------------------------------------------------------------------------------- 1 | // Intersection over Interface 2 | 3 | // - Interface Extends 4 | 5 | interface InterUser { 6 | id: string; 7 | name: string; 8 | } 9 | 10 | interface InterUser2 { 11 | id: number; 12 | address: string; 13 | } 14 | 15 | // We can have error IUser for 'id' identical 16 | interface IUser extends InterUser, InterUser2 {} 17 | 18 | const iUser: IUser = { 19 | id: "", 20 | name: "", 21 | address: "", 22 | }; 23 | 24 | // - Type Intersection 25 | 26 | type TypeUser = { 27 | id: string; 28 | name: string; 29 | }; 30 | 31 | type TypeUser2 = { 32 | id: number; 33 | address: string; 34 | }; 35 | 36 | // We don't get warning here 37 | type TUser = TypeUser & TypeUser2; 38 | 39 | const tUser: TUser = { 40 | id: "", // <- we got error here 41 | name: "", 42 | address: "", 43 | }; 44 | 45 | // We can't use 'interface' to define an union type directly. 46 | // Error: interface AorB = A | B 47 | // we can only use 'type' for union 48 | // eg: type AorB = A | B 49 | -------------------------------------------------------------------------------- /029-ts-readonly/index.ts: -------------------------------------------------------------------------------- 1 | type Person = { 2 | readonly id: number; 3 | name: string; 4 | }; 5 | 6 | const user: Person = { 7 | id: 1, 8 | name: "Lwin", 9 | }; 10 | 11 | // Able to update name 12 | user.name = "LMP"; 13 | 14 | // Showing error for readonly id 15 | // user.id = 2; 16 | 17 | type NumberArrays = readonly number[]; 18 | 19 | const nums: NumberArrays = [1, 2, 3]; 20 | 21 | // Showing error for readonly id 22 | // nums.push(1); 23 | // nums[0] = "1" 24 | -------------------------------------------------------------------------------- /030-ts-keyof/index.ts: -------------------------------------------------------------------------------- 1 | type User = { 2 | id: string; 3 | name: string; 4 | age: number; 5 | }; 6 | 7 | // The keys of User => "id" | "name" | "aage" 8 | type UserKeys = keyof User; 9 | 10 | // the Keys could be "name" | "age" 11 | type Keys = keyof { 12 | name: string; 13 | age: number; 14 | }; 15 | -------------------------------------------------------------------------------- /031-ts-typeof/index.ts: -------------------------------------------------------------------------------- 1 | // Basic Example: 2 | // TypeScript infers `username` is a string. 3 | let username = "John Doe"; 4 | 5 | // Using `typeof` to create a type based on `username`: 6 | type UsernameType = typeof username; 7 | 8 | // ✅ This works. 9 | const newUserName: UsernameType = "John Snow"; 10 | 11 | // ❌ Error: Type 'number' is not assignable to type 'string'. 12 | const invalidUsername: UsernameType = 123; 13 | 14 | // Real-world Example: Configurations 15 | const appConfig = { 16 | appName: "MyCoolApp", 17 | version: "1.0.0", 18 | debugMode: true, 19 | }; 20 | 21 | // Use `typeof` to create a type from the existing configuration object. 22 | type AppConfigType = typeof appConfig; 23 | 24 | // Now, `AppConfigType` is equivalent to: 25 | // type AppConfigType = { 26 | // appName: string; 27 | // version: string; 28 | // debugMode: boolean; 29 | // }; -------------------------------------------------------------------------------- /032-ts-index-type/index.ts: -------------------------------------------------------------------------------- 1 | // Type Indexing 2 | type StringObj = { 3 | [index: string]: string; 4 | }; 5 | 6 | const user: StringObj = { 7 | name: "Walker", 8 | age: "20", 9 | }; 10 | 11 | type Scores = { 12 | [key: string]: number; 13 | }; 14 | 15 | const myScore: Scores = { 16 | myanmar: 65, 17 | english: 50, 18 | mathematic: 80, 19 | }; 20 | 21 | type NoNo = { 22 | [index: number]: number; 23 | }; 24 | 25 | const noObj: NoNo = { 26 | 1: 100, 27 | "200.1": 20, 28 | }; 29 | -------------------------------------------------------------------------------- /033-ts-predefind-keys-by-default-with-index/index.ts: -------------------------------------------------------------------------------- 1 | // Predefined Keys 2 | 3 | type PremierLeagueScore = { 4 | manu: number; 5 | arsenal: number; 6 | liverpool: number; 7 | [team: string]: number; 8 | }; 9 | 10 | const teams: PremierLeagueScore = { 11 | manu: 5, 12 | arsenal: 4, 13 | liverpool: 1, 14 | 15 | // Other teams 16 | }; 17 | -------------------------------------------------------------------------------- /034-ts-union-keys-in-index/index.ts: -------------------------------------------------------------------------------- 1 | type Language = "mm" | "en"; 2 | 3 | type LangConfig = { 4 | [Lang in Language]: { 5 | color: string; 6 | fontSize: number; 7 | }; 8 | }; 9 | 10 | const langConfig: LangConfig = { 11 | mm: { 12 | color: "red", 13 | fontSize: 20, 14 | }, 15 | en: { 16 | color: "black", 17 | fontSize: 16, 18 | }, 19 | }; 20 | 21 | console.log(langConfig); 22 | -------------------------------------------------------------------------------- /035-ts-generic/index.ts: -------------------------------------------------------------------------------- 1 | function identity(value: T): T { 2 | return value; 3 | } 4 | 5 | // Example usage: 6 | const num = identity(42); // T is number 7 | const str = identity("Hello"); // T is string 8 | 9 | console.log(num); // Output: 42 10 | console.log(str); // Output: Hello 11 | 12 | // Example: Generic Interfaces 13 | interface Box { 14 | content: T; 15 | } 16 | 17 | const numberBox: Box = { content: 100 }; 18 | const stringBox: Box = { content: "TypeScript" }; 19 | 20 | console.log(numberBox.content); // Output: 100 21 | console.log(stringBox.content); // Output: TypeScript 22 | 23 | // Example: Api Response 24 | 25 | interface ApiResponse { 26 | status: number; 27 | data: T; 28 | } 29 | 30 | const userResponse: ApiResponse<{ id: string; name: string }> = { 31 | status: 200, 32 | data: { id: "123", name: "Alice" }, 33 | }; 34 | -------------------------------------------------------------------------------- /036-ts-async-function/index.ts: -------------------------------------------------------------------------------- 1 | const delay = (timeout: number) => { 2 | return new Promise((resolve) => 3 | setTimeout(() => { 4 | resolve("Return String"); 5 | }, timeout) 6 | ); 7 | }; 8 | 9 | // But when we call delay function 10 | // Response type will be Promise 11 | 12 | delay(1000); 13 | 14 | // so we can set response as type 15 | // e.g 16 | // delay = (timeout: number): Promise 17 | 18 | // or 19 | 20 | // You can make 21 | // new Promise(resolveFunction) 22 | -------------------------------------------------------------------------------- /037-ts-Pick/index.ts: -------------------------------------------------------------------------------- 1 | type ProductBaseType = { 2 | id: string; 3 | name: string; 4 | price: number; 5 | edit: boolean; 6 | loading: boolean; 7 | }; 8 | 9 | type Product = Pick; 10 | -------------------------------------------------------------------------------- /038-ts-Omit/index.ts: -------------------------------------------------------------------------------- 1 | type ProductType = { 2 | id: string; 3 | name: string; 4 | price: number; 5 | }; 6 | 7 | type AddProduct = Omit; 8 | 9 | const addProduct = (newProduct: AddProduct): ProductType => { 10 | const generatedId = Math.random() + ""; 11 | 12 | return { 13 | id: generatedId, 14 | name: newProduct.name, 15 | price: newProduct.price, 16 | }; 17 | }; 18 | 19 | addProduct({ name: "Apple", price: 100 }); -------------------------------------------------------------------------------- /039-ts-Partial/index.ts: -------------------------------------------------------------------------------- 1 | type ProductType = { 2 | id: string; 3 | name: string; 4 | price: number; 5 | description: string; 6 | }; 7 | 8 | const products: Array = [ 9 | { 10 | id: "1", 11 | name: "Product 1", 12 | price: 100, 13 | description: "Lorem", 14 | }, 15 | ]; 16 | 17 | type ProductWithoutID = Omit; 18 | 19 | type PartialProduct = Partial; 20 | 21 | const updateProductById = (id: string, data: PartialProduct) => { 22 | const index = products.findIndex((prod) => prod.id === id); 23 | if (index > 0) { 24 | products[index] = { 25 | ...products[index], 26 | ...data, 27 | }; 28 | } 29 | }; 30 | 31 | updateProductById("1", { price: 200 }); 32 | 33 | updateProductById("1", { name: "Edited Product Name" }); 34 | 35 | updateProductById("1", { description: "New Desc", price: 10 }); 36 | -------------------------------------------------------------------------------- /040-ts-Required/index.ts: -------------------------------------------------------------------------------- 1 | // Example: 2 | // Start with a type where all properties are optional: 3 | type PartialSquare = { 4 | width?: number; 5 | height?: number; 6 | }; 7 | 8 | // Use the `Required` 9 | type Square = Required; 10 | 11 | const square: Square = { 12 | width: 100, 13 | height: 100, 14 | }; 15 | 16 | // Imagine a configuration with optional: 17 | type Config = { 18 | apiKey?: string; 19 | debugMode?: boolean; 20 | }; 21 | 22 | // You want to enforce 23 | // that all properties are provided at runtime: 24 | type FullConfig = Required; 25 | 26 | // ✅ This works. 27 | const validConfig: FullConfig = { 28 | apiKey: "12345", 29 | debugMode: true, 30 | }; 31 | 32 | // ❌ Error: Property 'debugMode' is missing in 33 | // type '{ apiKey: string; }' but required in type 'FullConfig'. 34 | const invalidConfig: FullConfig = { 35 | apiKey: "12345", 36 | }; 37 | -------------------------------------------------------------------------------- /041-ts-Record/index.ts: -------------------------------------------------------------------------------- 1 | type UserType = { 2 | [index: string]: string; 3 | }; 4 | 5 | const user: UserType = { 6 | name: "LMP", 7 | }; 8 | 9 | type PlayerType = Record; 10 | 11 | const player: PlayerType = { 12 | name: "Player One", 13 | }; 14 | 15 | type Item = { 16 | name: string; 17 | price: number; 18 | }; 19 | 20 | type OrderList = Record; 21 | 22 | const orderList: OrderList = { 23 | order1: { name: "Apple", price: 200 }, 24 | order2: { name: "Apple", price: 200 }, 25 | }; 26 | -------------------------------------------------------------------------------- /042-ts-Readonly/index.ts: -------------------------------------------------------------------------------- 1 | type Todo = { 2 | title: string; 3 | done: boolean; 4 | }; 5 | 6 | const updatableTodo: Todo = { 7 | title: "Todo Title", 8 | done: false, 9 | }; 10 | 11 | updatableTodo.done = true; 12 | 13 | type DoneTodo = Readonly; 14 | const doneTodo: DoneTodo = { 15 | title: "Todo Title", 16 | done: false, 17 | }; 18 | 19 | // Cannot assign to 'done' 20 | doneTodo.done = true; 21 | 22 | // Readonly Todo with Object Freeze 23 | const transformTodo = Object.freeze(updatableTodo); 24 | transformTodo.done = false; 25 | -------------------------------------------------------------------------------- /043-ts-as-type-casting/index.ts: -------------------------------------------------------------------------------- 1 | // 1. Example: "as" Casting 2 | const value: unknown = "hello"; 3 | const stringValue = value as string; // Assert 'value' as a string 4 | console.log(stringValue.toUpperCase()); // HELLO 5 | 6 | // 2. Example: Type Assertion with Fetch API 7 | type User = { 8 | id: string; 9 | name: string; 10 | }; 11 | 12 | const fetchUser = async (): Promise => { 13 | const response = await fetch("https://example-backend.com/api/v1/user"); 14 | 15 | // The response from `response.json()` is typed as `any` 16 | const parsedData = await response.json(); 17 | 18 | // Assert that the parsed data conforms to the 'User' type 19 | const userData = parsedData as User; 20 | 21 | return userData; 22 | }; 23 | 24 | // Usage Example 25 | (async () => { 26 | const user = await fetchUser(); 27 | console.log(`User: ${user.name}, ID: ${user.id}`); 28 | })(); 29 | -------------------------------------------------------------------------------- /044-ts-satisfies/index.ts: -------------------------------------------------------------------------------- 1 | type User = { 2 | id: string; 3 | name: string; 4 | role: "admin" | "user"; 5 | createdAt: Date | string; 6 | }; 7 | 8 | const getUserName = (user: User) => { 9 | return user.name; 10 | }; 11 | 12 | const normalUser: User = { 13 | id: "1", 14 | name: "John Doe", 15 | role: "user", 16 | createdAt: new Date(), 17 | }; 18 | 19 | // Can't use toDateString method of Date type 20 | // because createdAt could be 'string' type 21 | normalUser.createdAt.toDateString(); 22 | 23 | const userLMP = { 24 | id: "1", 25 | name: "Lwin Moe Paing", 26 | role: "user", 27 | createdAt: new Date(), 28 | } satisfies User; 29 | 30 | getUserName(userLMP); 31 | 32 | // createdAt type is sure 'Date' type with satisfies 33 | userLMP.createdAt.toDateString(); 34 | -------------------------------------------------------------------------------- /045-ts-different-scope-narrowing/index.ts: -------------------------------------------------------------------------------- 1 | const convertNumber = (value: string | number) => { 2 | if (typeof value === "string") { 3 | // Vaule type will be "string" in this scope 4 | console.log(value); 5 | console.log(value.toUpperCase()); 6 | } else { 7 | // Vaule type will be "number" in this scope 8 | console.log(value); 9 | console.log(value.toLocaleString()); 10 | } 11 | 12 | // Value Type will be "number" or "string" in this scope 13 | console.log("String or Number: ", value); 14 | }; 15 | 16 | // Conditional Narrowing with "If" statement 17 | const validatePassword = (password: string | null): boolean => { 18 | // This will show error because "password" could be null 19 | // return password.length > 5; 20 | 21 | if (password) { 22 | return password.length > 6; 23 | } 24 | 25 | return false; 26 | }; 27 | 28 | type Event = { 29 | message: string; 30 | }; 31 | 32 | const processEventMap = (eventMap: Map) => { 33 | // This example will get error 34 | // because event.has can not be unknown when it get inside if scope 35 | // if (eventMap.has("error")) { 36 | // const message = eventMap.get("error").message; 37 | // } 38 | 39 | const errorEvent = eventMap.get("error"); 40 | 41 | if (errorEvent) { 42 | const message = errorEvent.message; 43 | } 44 | }; 45 | 46 | // Conditional Narrowing with "in" statement 47 | type Response = 48 | | { 49 | data: { 50 | id: string; 51 | }; 52 | } 53 | | { error: Error }; 54 | 55 | const handleResponse = (res: Response) => { 56 | if ("data" in res) { 57 | return res.data.id; 58 | } 59 | 60 | return res.error; 61 | }; 62 | 63 | // Narrowing with "instance of" 64 | const getUser = () => { 65 | try { 66 | // Some login to fetch user data... 67 | } catch (error) { 68 | if (error instanceof Error) { 69 | console.error(error); 70 | } 71 | } 72 | }; 73 | 74 | // Narrowing in Different Scope 75 | type User = { id: string; name: string }; 76 | const users: Array = [ 77 | { id: "1", name: "Lwin" }, 78 | { id: "2", name: "Moe" }, 79 | { id: "3", name: "Paing" }, 80 | ]; 81 | 82 | // This example will show error 83 | // const findUserByName = (search: { name?: string }) => { 84 | // if (search.name) { 85 | // // We can still update search.name = "blah blah" 86 | // // or empty string here!! 87 | // return users.filter((user) => { 88 | // return user.name.includes(search.name); 89 | // }); 90 | // } 91 | // return users; 92 | // }; 93 | 94 | const findUserByName = (search: { name?: string }) => { 95 | const searchName = search.name; 96 | if (searchName) { 97 | return users.filter((user) => { 98 | return user.name.includes(searchName); 99 | }); 100 | } 101 | return users; 102 | }; 103 | 104 | findUserByName({}); 105 | findUserByName({ name: "Moe" }); 106 | -------------------------------------------------------------------------------- /046-ts-narrowing-with-discriminated-union/index.ts: -------------------------------------------------------------------------------- 1 | type DataResponse = { 2 | status: "ok"; 3 | data: { 4 | id: string; 5 | }; 6 | }; 7 | 8 | type ErrorResponse = { 9 | status: "error"; 10 | error: Error; 11 | }; 12 | 13 | type ResponseProps = DataResponse | ErrorResponse; 14 | 15 | const responseHandler = (response: ResponseProps) => { 16 | if (response.status === "ok") { 17 | return response.data; 18 | } 19 | 20 | return response.error; 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /047-ts-narrowing-with-discriminated-union-switch-statement/index.ts: -------------------------------------------------------------------------------- 1 | type DefaultItemType = { 2 | itemName: string; 3 | itemPrice: number; 4 | }; 5 | 6 | type DeliveryType = { 7 | id: string; 8 | name: string; 9 | }; 10 | 11 | type ReceiveUser = { 12 | id: string; 13 | name: string; 14 | address: string; 15 | }; 16 | 17 | type PendingOrder = { 18 | status: "pending"; 19 | } & DefaultItemType; 20 | 21 | type OnGoingOrder = { 22 | status: "ongoing"; 23 | delivery: DeliveryType; 24 | } & DefaultItemType; 25 | 26 | type CompleteOrder = { 27 | status: "completed"; 28 | delivery: DeliveryType; 29 | receiver: ReceiveUser; 30 | } & DefaultItemType; 31 | 32 | type OrderUnion = PendingOrder | OnGoingOrder | CompleteOrder; 33 | 34 | const checkOrder = (order: OrderUnion) => { 35 | switch (order.status) { 36 | case "pending": 37 | console.log(order.status); 38 | break; 39 | 40 | case "ongoing": 41 | console.log(order.delivery); 42 | break; 43 | 44 | case "completed": 45 | console.log(order.receiver); 46 | break; 47 | } 48 | }; 49 | 50 | const pendingOrder: PendingOrder = { 51 | status: "pending", 52 | itemName: "Apple", 53 | itemPrice: 1000, 54 | }; 55 | 56 | const onGoingOrder: OnGoingOrder = { 57 | status: "ongoing", 58 | itemName: "Orange", 59 | itemPrice: 800, 60 | delivery: { 61 | id: "100", 62 | name: "Lwin", 63 | }, 64 | }; 65 | 66 | const receiver: CompleteOrder = { 67 | status: "completed", 68 | itemName: "Orange", 69 | itemPrice: 800, 70 | delivery: { 71 | id: "100", 72 | name: "Lwin", 73 | }, 74 | receiver: { 75 | id: "1", 76 | name: "Moe", 77 | address: "YGN", 78 | }, 79 | }; 80 | 81 | // Testing 82 | checkOrder(receiver); 83 | -------------------------------------------------------------------------------- /048-ts-is-predicates-type-guard/index.ts: -------------------------------------------------------------------------------- 1 | const checkNumber = (value: string | number): value is number => { 2 | return typeof value === "number"; 3 | }; 4 | 5 | const printLucky = (value: string | number) => { 6 | if (checkNumber(value)) { 7 | console.log("Your Lucky number is", value); 8 | } else { 9 | console.log(`Ohh! You are lucky, ${value}`); 10 | } 11 | }; 12 | 13 | type BasedUser = { id: string; name: string }; 14 | 15 | type NormalUser = BasedUser & { 16 | role: "user"; 17 | userInfo: string; 18 | }; 19 | 20 | type AdminUser = BasedUser & { 21 | role: "admin"; 22 | adminInfo: string; 23 | adminData: string; 24 | }; 25 | 26 | const checkAdmin = (user: AdminUser | NormalUser): user is AdminUser => 27 | user.role === "admin"; 28 | 29 | const orderProduct = (user: AdminUser | NormalUser) => { 30 | // check admin user 31 | if (checkAdmin(user)) { 32 | console.log(user.adminInfo); 33 | console.log(user.adminData); 34 | } else { 35 | console.log(user.userInfo); 36 | } 37 | }; 38 | 39 | const getAllAdminUsers = (users: (AdminUser | NormalUser)[]): AdminUser[] => { 40 | const allAdminUsers = users.filter(checkAdmin); 41 | return allAdminUsers; 42 | }; 43 | -------------------------------------------------------------------------------- /049-ts-assertion-predicates-type-guard/index.ts: -------------------------------------------------------------------------------- 1 | type BasedUser = { id: string; name: string }; 2 | 3 | type NormalUser = BasedUser & { 4 | role: "user"; 5 | userInfo: string; 6 | }; 7 | 8 | type AdminUser = BasedUser & { 9 | role: "admin"; 10 | adminInfo: string; 11 | adminData: string; 12 | }; 13 | 14 | type AssertAdminFn = ( 15 | user: AdminUser | NormalUser 16 | ) => asserts user is AdminUser; 17 | 18 | const checkIsAdmin: AssertAdminFn = (user) => { 19 | if (user.role !== "admin") throw new Error("Only access for Admin User"); 20 | }; 21 | 22 | const actionForAdmin = (user: AdminUser | NormalUser) => { 23 | try { 24 | checkIsAdmin(user); 25 | console.log(user.adminInfo); 26 | } catch {} 27 | }; 28 | -------------------------------------------------------------------------------- /050-ts-class/index.ts: -------------------------------------------------------------------------------- 1 | class Car { 2 | constructor(public name: string) {} 3 | } 4 | 5 | const car = new Car("BMW"); -------------------------------------------------------------------------------- /For-Ts-eBook.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lwinmoepaing/typescript-baby/b28705abdd327084960995529f2dae90337e2f1d/For-Ts-eBook.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### **TypeScript Baby by Lwin Moe Paing** 2 | 3 | This structure introduces TypeScript in a friendly and practical way, providing clear examples and actionable steps for beginners to follow. -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleDetection": "force", 4 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 5 | "module": "commonjs" /* Specify what module code is generated. */, 6 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 7 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 8 | "strict": true /* Enable all strict type-checking options. */, 9 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 10 | } 11 | } 12 | --------------------------------------------------------------------------------