├── .gitignore ├── LICENSE ├── README.md └── cheatsheet ├── assets ├── intro.png └── logo.png ├── ts.md └── ts.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Leonardo Folgoni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ts-extended-cheatsheet 2 | An extended cheatsheet about TypeScript 3 | 4 | ## DISCLAIMER 5 | 6 | This is not a full, well-curated documentation about TypeScript. These are the notes I took following various sources while learning TypeScript. I'm Italian, so sorry for the not so perfect English. 7 | 8 | ## Cheatsheet 9 | 10 | MD: [HERE](https://github.com/f0lg0/ts-extended-cheatsheet/blob/master/cheatsheet/ts.md) 11 | 12 | PDF: [HERE](https://github.com/f0lg0/ts-extended-cheatsheet/blob/master/cheatsheet/ts.pdf) 13 | 14 | -------------------------------------------------------------------------------- /cheatsheet/assets/intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/ts-extended-cheatsheet/e66c1aaea0558b77d4246f81348aa2e2d94cd63b/cheatsheet/assets/intro.png -------------------------------------------------------------------------------- /cheatsheet/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/ts-extended-cheatsheet/e66c1aaea0558b77d4246f81348aa2e2d94cd63b/cheatsheet/assets/logo.png -------------------------------------------------------------------------------- /cheatsheet/ts.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

TypeScript

6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [TypeScript](#typescript) 11 | * [Introduction](#introduction) 12 | * [What is TypeScript?](#what-is-typescript) 13 | * [What does it add?](#what-does-it-add) 14 | * [Why TypeScript?](#why-typescript) 15 | * [Requirements](#requirements) 16 | * [Install typescript](#install-typescript) 17 | * [Overview](#overview) 18 | * [Basics](#basics) 19 | * [Core Types](#core-types) 20 | * [Using types](#using-types) 21 | * [Type Inference](#type-inference) 22 | * [Object types](#object-types) 23 | * [Array types](#array-types) 24 | * [More Types](#more-types) 25 | * [Tuples](#tuples) 26 | * [Enum](#enum) 27 | * [Union Types](#union-types) 28 | * [Literal Types](#literal-types) 29 | * [Type Aliases](#type-aliases) 30 | * [Function Return Types](#function-return-types) 31 | * [Function as Types](#function-as-types) 32 | * [Unknown Type](#unknwon-type) 33 | * [Never Type](#never-type) 34 | * [TS Compiler](#ts-compiler) 35 | * [Command Options](#command-options) 36 | * [Flags in tsconfig](#flags-in-tsconfig) 37 | * [Classes and Interfaces](#classes-and-interfaces) 38 | * [Classes](#classes) 39 | * [Private Modifiers](#private-modifiers) 40 | * [Public Modifiers](#public-modifiers) 41 | * [Shorthand Initialization](#shorthand-initialization) 42 | * [Read-only Modifier](#read-only-modifier) 43 | * [Inheritance](#inheritance) 44 | * [Getters and Setters](#getters-and-setters) 45 | * [Static Properties and Methods](#static-properties-and-methods) 46 | * [Abstract Classes](#absract-classes) 47 | * [Private Constructors](#private-constructors) 48 | * [Interfaces](#interfaces) 49 | * [Interfaces with Classes](#interfaces-with-classes) 50 | * [Inheritance with Interfaces](#inheritance-with-interfaces) 51 | * [Interfaces as Function Types](#interfaces-as-function-types) 52 | * [Optional Parameters](#optional-parameters) 53 | * [Advanced Types Concepts](#advanced-types-concepts) 54 | * [Intersection Types](#intersection-types) 55 | * [Type Guards](#type-guards) 56 | * [Discriminated Unions](#discriminated-unions) 57 | * [Type Casting](#type-casting) 58 | * [Index Properties](#index-properties) 59 | * [Function Overloads](#function-overloads) 60 | * [Optional Chaining](#optional-chaining) 61 | * [Nullish Coalescing](#nullish-coalescing) 62 | * [Generics](#generics) 63 | * [What are generics?](#what-are-generics) 64 | * [Custom Generic](#custom-generic) 65 | * [Functions](#functions) 66 | * [Constraints](#constraints) 67 | * [KeyOf Constraint](#keyof-constraint) 68 | * [Generic Classes](#generic-classes) 69 | * [Generic Utility Types](#generic-utility-types) 70 | * [Partial](#partial) 71 | * [Readonly](#readonly) 72 | * [Generic vs Union Types?](#generic-vs-union-types) 73 | * [Decorators](#decorators) 74 | * [DISCLAIMER](#disclaimer) 75 | * [Decorators Factories](#decorators-factories) 76 | * [Example](#example) 77 | * [Property Decorators](#property-decorators) 78 | * [Returning in a decorator](#returning-in-a-decorator) 79 | * [Modules](#modules) 80 | * [Namespaces and File Bundling](#namespaces-and-file-bundling) 81 | * [Result](#result) 82 | * [ES6 Modules](#es6-modules) 83 | * [Syntax](#syntax) 84 | * [tsconfig](#tsconfig) 85 | * [IMPORTANT](#important) 86 | * [Webpack](#webpack) 87 | * [What is Webpack?](#what-is-webpack) 88 | * [Install](#install) 89 | * [Configurations](#configurations) 90 | * [How to use Webpack](#how-to-use-webpack) 91 | * [Dev Workflow](#dev-workflow) 92 | * [Production Workflow](#production-workflow) 93 | * [Useful Requirements](#useful-requirements) 94 | * [NodeJS and Express](#nodejs-and-express) 95 | * [Useful stuff](#useful-stuff) 96 | * [Credits](#credits) 97 | 98 | 99 | # Introduction 100 | 101 | ## What is TypeScript? 102 | 103 | TypeScript is a JavaScript superset, which means that it is a language that builds up on JavaScript. It adds **new features and advantages** to JS. 104 | 105 | Browsers and Node.js can't execute TypeScript. 106 | 107 | TypeScript is more of a compiler that compiles code to JavaScript, it basically transforms your code into JS. 108 | 109 | ![intro](./assets/intro.png) 110 | 111 | ### What does it add? 112 | 113 | Most importantly, as the name suggests, it adds ``types`` to the JS language. This can be useful to prevent ``runtime`` errors. 114 | 115 | ## Why TypeScript? 116 | 117 | Let's assume this JS code: 118 | 119 | ```javascript 120 | function add(num1, num2) { 121 | return num1 + num2; 122 | } 123 | 124 | add("1", "2"); 125 | ``` 126 | 127 | We are passing strings to a function that should sum two numbers, this won't generate an error in JS but we will not receive the expected output (unwanted behavior at Runtime). 128 | 129 | To fix this in JS we would need to do something like: 130 | 131 | ```javascript 132 | if (typeof num1 === "number" && typeof num2 === "number") 133 | ``` 134 | 135 | TypeScript can really help us in situations like this: 136 | 137 | ```typescript 138 | function add(num1: number, num2: number) { 139 | return num1 + num2; 140 | } 141 | ``` 142 | 143 | With this extra syntax we openly state that we should only expect numbers. 144 | 145 | 146 | 147 | ## Requirements 148 | 149 | * Node.js 150 | * TypeScript npm package 151 | 152 | ### Install typescript 153 | 154 | ``npm i -g typescrypt`` 155 | 156 | 157 | 158 | ## Overview 159 | 160 | TypeScript adds: 161 | 162 | * Types 163 | * Next-gen JS Features compiled down for older Browsers 164 | * More features such as Interfaces or Generics 165 | * Meta-Programming Features like Decorators 166 | * Rich Configuration Options 167 | * Modern tooling that helps even non TypeScript Projects (especially in IDEs). 168 | 169 | 170 | 171 | # Basics 172 | 173 | ## Core Types 174 | 175 | In TypeScript we have the following types (and more): 176 | 177 | * number (all numbers) 178 | * string 179 | * boolean 180 | * no truthy or falsy values 181 | * object 182 | * array 183 | * any 184 | * it is as flexible as writing normal JS 185 | * undefined 186 | * Function 187 | * unknown 188 | * a value that is not guaranteed to be something. 189 | * void 190 | * never 191 | 192 | 193 | 194 | ### Using types 195 | 196 | ```typescript 197 | function add (num1: number, num2: number) { 198 | return num1 + num2; 199 | } 200 | 201 | const n1 = 10; 202 | const n2 = 3.2; 203 | 204 | const result = add(n1, n2); 205 | ``` 206 | 207 | **TypeScript's type system only helps you during development**. 208 | 209 | 210 | 211 | ### Type Inference 212 | 213 | TypeScript is smart enough to recognize some non-explicit variable types such as 214 | 215 | ```typescript 216 | let number1 = 5; // number1: number 217 | ``` 218 | 219 | We could do 220 | 221 | ```typescript 222 | let number1: number = 1; 223 | ``` 224 | 225 | We can also declare variables without values: 226 | 227 | ```typescript 228 | const n1: number; 229 | ``` 230 | 231 | 232 | 233 | ### Object types 234 | 235 | Object properties in TS are stricter than in JS, if we have a `person` object: 236 | 237 | ```typescript 238 | const person = { 239 | name: 'Leonardo', 240 | age: 17 241 | }; 242 | ``` 243 | 244 | We can't access `person.nickname`. 245 | 246 | This is a 'generic' object, in TS we can be more specific: 247 | 248 | ```typescript 249 | const person: { name: string, age: number } = { 250 | name: 'Leonardo', 251 | age: 17 252 | }; 253 | ``` 254 | 255 | In this case the object **must only have** a name property and an age property. 256 | 257 | But this is not `best practice` since TS can pick it up on its own just by doing like in the example before this one. 258 | 259 | 260 | 261 | ### Array types 262 | 263 | TS describes an array with ``type[]`` where type can be `string, number ...` 264 | 265 | So we can declare an array like this: 266 | 267 | ```typescript 268 | const arr: string[]; 269 | ``` 270 | 271 | And we can only add strings. 272 | 273 | If we want a `mixed` array we can use the `any` type. 274 | 275 | 276 | 277 | ## More Types 278 | 279 | TS has some new types. 280 | 281 | 282 | 283 | ### Tuples 284 | 285 | Fixed length and fixed content arrays. 286 | 287 | ```typescript 288 | const person: { name: string, age: number, role: [number, string] } = { 289 | name: 'Leonardo', 290 | age: 17, 291 | role: [1, 'admin'] 292 | }; 293 | ``` 294 | 295 | **NOTE:** ``push`` is allowed in tuples even if, in this example, you can't manually create a 'role' tuple with more than 2 elements (or less than 2). 296 | 297 | 298 | 299 | ### Enum 300 | 301 | They assign labels to numbers and are useful for constant identifiers. 302 | 303 | ```typescript 304 | enum Role { ADMIN, READ_ONLY, AUTHOR }; 305 | 306 | const person: { 307 | name: string, 308 | age: number, 309 | role: Role.ADMIN 310 | } = { 311 | name: 'Leonardo', 312 | age: 17, 313 | role: [1, 'admin'] 314 | }; 315 | ``` 316 | 317 | We can assign custom **values** (numbers...) to them if we want. 318 | 319 | ```typescript 320 | enum Role { ADMIN = 100, READ_ONLY = "abc", AUTHOR = 12 }; 321 | ``` 322 | 323 | 324 | 325 | ## Union Types 326 | 327 | We can specify more than a type to a variable with `union types`. 328 | 329 | ```typescript 330 | const someVariable: string | number; 331 | ``` 332 | 333 | 334 | 335 | ## Literal Types 336 | 337 | Literal types are used to specify a precise value to assign to a variable. Especially useful for string identifiers or flags. 338 | 339 | ```typescript 340 | function doSomething(param1: number, param2: number, flag: 'do-this' | 'dont-do-this') { 341 | // code... 342 | } 343 | ``` 344 | 345 | 346 | 347 | Here `flag` can only be: 348 | 349 | * do-this 350 | * dont-do-this 351 | 352 | 353 | 354 | ## Type Aliases 355 | 356 | We can create aliases for types: 357 | 358 | ```typescript 359 | type MyCustomType = number | string; 360 | type AnotherType = ':)'; 361 | ``` 362 | 363 | 364 | 365 | ## Function Return Types 366 | 367 | We can specify a return type to returns: 368 | 369 | ```typescript 370 | function printResult (n1: number, n2: number): void { 371 | console.log('Result: ', + (n1+ n2)); 372 | } 373 | ``` 374 | 375 | We obviously don't need to specify it in this case. 376 | 377 | 378 | 379 | ### Function as Types 380 | 381 | Variables can hold a ``function``. 382 | 383 | ```typescript 384 | const someVariable: Function; 385 | ``` 386 | 387 | We can even be more specific by doing: 388 | 389 | ```typescript 390 | // this is a function with NO arguments that returns a NUMBER 391 | const temp = () => number; 392 | ``` 393 | 394 | This can also be useful to specify ``callbacks``. 395 | 396 | ## Unknown Type 397 | 398 | Unknown is more restrictive than `any`. 399 | 400 | For example we CAN'T do: 401 | 402 | ```typescript 403 | let a: unknown; 404 | let b: string; 405 | 406 | a = 5; 407 | a = 'abc'; 408 | 409 | // NO 410 | b = a; 411 | ``` 412 | 413 | This example would work in case of the `any` type. 414 | 415 | ## Never Type 416 | 417 | ```typescript 418 | function generateError(message: string, code: number): never { 419 | throw { message: message, errorCode: code}; 420 | } 421 | 422 | generateCode('Error Message', 500); 423 | ``` 424 | 425 | This function `never` returns a value. It is a special case (it crashes our program and stops there). 426 | 427 | 428 | 429 | # TS Compiler 430 | 431 | To compile code we run ``tsc file.ts``. But we can configure it with a `tsconfig.json`. 432 | 433 | ## Command Options 434 | 435 | | --watch | Watch Mode to avoid compiling a file every time | 436 | | ------- | ------------------------------------------------------------ | 437 | | --init | Init a project (compile multiple files and create tsconfig.json) | 438 | 439 | ## Flags in tsconfig 440 | 441 | | exclude | exclude files from compilation / node_modules | 442 | | ------------- | ------------------------------------------------------------ | 443 | | include | include files for compilation | 444 | | files | points/specify files | 445 | | target | ECMAScript target version | 446 | | module | module system | 447 | | lib | specify libraries (DOM) | 448 | | checkJs | reports errors in .js files | 449 | | sourcemap | bridge to connect the js files to the input ts files (we can see ts files in the source tab in the browser) | 450 | | outDir | specify where the created js will be stored | 451 | | rootDir | specify where to grab the ts files | 452 | | noEmitOnError | don't emit js files if an error occurs | 453 | 454 | And many more. 455 | 456 | 457 | 458 | # Classes and Interfaces 459 | 460 | ## Classes 461 | 462 | ```typescript 463 | class Department { 464 | // attributes 465 | name: string; 466 | 467 | // constructor 468 | constructor(n: string) { 469 | this.name = n; 470 | } 471 | 472 | // methods 473 | printName(this: Department) { // ts feature to specify that this method should run only on a Department object 474 | console.log(this.name); 475 | } 476 | } 477 | 478 | const dep = new Department('Dep Name'); 479 | ``` 480 | 481 | 482 | 483 | ### Private Modifiers 484 | 485 | ```typescript 486 | class Department { 487 | private name: string; 488 | private employees: string[] = []; 489 | 490 | constructor(n: string) { 491 | this.name = n; 492 | } 493 | 494 | printName(this: Department) { 495 | console.log(this.name); 496 | } 497 | 498 | addEmployee(employee: string) { 499 | this.employees.push(employee); 500 | } 501 | } 502 | ``` 503 | 504 | Properties are now accessible only in the class (not in [child](#Inheritance) classes). 505 | 506 | In order to share `private` properties to child classes thru [Inheritance](#Inheritance) use the `protected` keyword. 507 | 508 | 509 | 510 | ### Public Modifiers 511 | 512 | Public is the default option so we don't need to set it. 513 | 514 | ```typescript 515 | class Department { 516 | public name: string; 517 | public employees: string[] = []; 518 | 519 | constructor(n: string) { 520 | this.name = n; 521 | } 522 | 523 | printName(this: Department) { 524 | console.log(this.name); 525 | } 526 | 527 | addEmployee(employee: string) { 528 | this.employees.push(employee); 529 | } 530 | } 531 | ``` 532 | 533 | 534 | 535 | ### Shorthand Initialization 536 | 537 | ```typescript 538 | class Department { 539 | // public name: string; 540 | // public employees: string[] = []; 541 | 542 | constructor(private name: string, public employees: string[]) { 543 | // this.name = n; 544 | } 545 | 546 | printName(this: Department) { 547 | console.log(this.name); 548 | } 549 | 550 | addEmployee(employee: string) { 551 | this.employees.push(employee); 552 | } 553 | } 554 | ``` 555 | 556 | 557 | 558 | ### Read-only Modifier 559 | 560 | ```typescript 561 | class Department { 562 | private readonly name: string; 563 | private employees: string[] = []; 564 | 565 | constructor(n: string) { 566 | this.name = n; 567 | } 568 | 569 | printName(this: Department) { 570 | console.log(this.name); 571 | } 572 | 573 | addEmployee(employee: string) { 574 | this.employees.push(employee); 575 | } 576 | } 577 | ``` 578 | 579 | We can't modify the name property. 580 | 581 | 582 | 583 | ### Inheritance 584 | 585 | ```typescript 586 | class Department { 587 | private readonly name: string; 588 | private employees: string[] = []; 589 | 590 | constructor(n: string) { 591 | this.name = n; 592 | } 593 | 594 | printName(this: Department) { 595 | console.log(this.name); 596 | } 597 | 598 | addEmployee(employee: string) { 599 | this.employees.push(employee); 600 | } 601 | } 602 | 603 | class ITDepartment extends Department { 604 | constructor(id: string) { 605 | super('IT'); 606 | this.id = id; 607 | } 608 | } 609 | ``` 610 | 611 | We can also override parent methods in child classes by re-declaring them. 612 | 613 | 614 | 615 | ### Getters and Setters 616 | 617 | In order to access `private` attributes from the outside of a class we can implement `getters` and `setters`. 618 | 619 | ```typescript 620 | class Department { 621 | private name: string; 622 | 623 | constructor(n: string) { 624 | this.name = n; 625 | } 626 | 627 | get name(this: Department) { 628 | return this.name; 629 | } 630 | 631 | set name(value: string) { 632 | this.name = value; 633 | } 634 | 635 | } 636 | 637 | const d = new Department(); 638 | 639 | // Getter 640 | console.log(d.name) // with no () 641 | 642 | // Setter 643 | d.name = "Name"; 644 | ``` 645 | 646 | We access them as `properties` and not methods. 647 | 648 | 649 | 650 | ### Static Properties and Methods 651 | 652 | Properties and Methods that we don't access from an instance. An example is `Math`. 653 | 654 | ```typescript 655 | class Department { 656 | private name: string; 657 | 658 | constructor(n: string) { 659 | this.name = n; 660 | } 661 | 662 | static createEmployee(name: string) { 663 | return { name: name }; 664 | } 665 | 666 | } 667 | 668 | Department.createEmployee('Leo'); 669 | ``` 670 | 671 | 672 | 673 | ### Abstract Classes 674 | 675 | Back to Inheritance, we can force developers to implement a certain method in a class (especially child ones). 676 | 677 | ```typescript 678 | abstract class Department { 679 | private readonly name: string; 680 | private employees: string[] = []; 681 | 682 | constructor(n: string) { 683 | this.name = n; 684 | } 685 | 686 | printName(this: Department) { 687 | console.log(this.name); 688 | } 689 | 690 | addEmployee(employee: string) { 691 | this.employees.push(employee); 692 | } 693 | 694 | // we are just saying that every child must implement this method. 695 | abstract mandatoryMethod(this: Department): void; 696 | } 697 | 698 | class ITDepartment extends Department { 699 | constructor(id: string) { 700 | super('IT'); 701 | this.id = id; 702 | } 703 | 704 | mandatoryMethod() { 705 | // code 706 | } 707 | } 708 | ``` 709 | 710 | `abstract` classes **CAN'T BE INSTANTIATED** 711 | 712 | 713 | 714 | ### Private Constructors 715 | 716 | Singleton Pattern = have only one instance of a class. 717 | 718 | With private constructors we can't use `new ClassName()` outside of the class. 719 | 720 | ```typescript 721 | class ITDepartment extends Department { 722 | // we need to provide an instance otherwise we can't create it with the 'new' keyword 723 | private static instance: ITDepartment; 724 | 725 | private constructor(id: string) { 726 | super('IT'); 727 | this.id = id; 728 | } 729 | 730 | static getInstance() { 731 | if (ITDepartment.instance) { 732 | return this.instance; 733 | } 734 | 735 | this.instance = new ITDepartment(); 736 | } 737 | } 738 | 739 | const it = ITDepartment.getInstance(); 740 | const it2 = ITDepartment.getInstance(); 741 | 742 | // it === it2 743 | ``` 744 | 745 | 746 | 747 | ## Interfaces 748 | 749 | An interfaces describes the structure of an object (not the same thing as a custom type). 750 | 751 | ```typescript 752 | interface Person { 753 | name: string; 754 | age: number; 755 | 756 | printName(): void; 757 | } 758 | 759 | let user: Person; 760 | 761 | user = { 762 | name: 'Leonardo', 763 | age: 17, 764 | printName: function () { 765 | console.log(this.name); 766 | } 767 | } 768 | ``` 769 | 770 | We can also add `readonly` to properties. 771 | 772 | ### Interfaces with Classes 773 | 774 | We can implement an interface in a class. 775 | 776 | ```typescript 777 | interface Greetable { 778 | name: string; 779 | 780 | greet(): void; 781 | } 782 | 783 | class Person implements Greetable { 784 | name: string; 785 | 786 | constructor(name: string) { 787 | this.name = name; 788 | } 789 | 790 | greet() { 791 | console.log(this.name); 792 | } 793 | } 794 | 795 | let user: Greetable; 796 | 797 | user = new Person('Leo'); 798 | ``` 799 | 800 | The interface acts like a strict blueprint. 801 | 802 | 803 | 804 | ### Inheritance with Interfaces 805 | 806 | ```typescript 807 | interface Named { 808 | readonly name: string 809 | } 810 | 811 | interface Greetable extends Named { 812 | greet(): void 813 | } 814 | 815 | interface AnotherInterface { 816 | readonly someValue: string 817 | } 818 | 819 | class Person implements Greetable, AnotherInterface { 820 | name: string; 821 | someValue: string; 822 | 823 | constructor(name: string) { 824 | this.name = name; 825 | } 826 | 827 | greet() { 828 | console.log(this.name); 829 | } 830 | } 831 | ``` 832 | 833 | 834 | 835 | ### Interfaces as Function Types 836 | 837 | ```typescript 838 | interface AddFn { 839 | (a: number, b:number): number; 840 | } 841 | 842 | let add: AddFn; 843 | 844 | add = (n1: number, n2: number) => { 845 | return n1 + n2; 846 | } 847 | ``` 848 | 849 | 850 | 851 | ### Optional Parameters 852 | 853 | ```typescript 854 | interface Person { 855 | name: string; 856 | lastName?: string 857 | } 858 | ``` 859 | 860 | `lastName` will be optional 861 | 862 | **We can have optional parameters even in function and classes.** 863 | 864 | 865 | 866 | # Advanced Types Concepts 867 | 868 | 869 | 870 | ## Intersection Types 871 | 872 | ```typescript 873 | type Admin = { 874 | name: string; 875 | priviliges: string[]; 876 | }; 877 | 878 | type Employee = { 879 | name: string; 880 | startDate: Date; 881 | }; 882 | 883 | type ElevatedEmployee = Admin & Employee; 884 | ``` 885 | 886 | It's the same thing as `extending` interfaces. 887 | 888 | ```typescript 889 | type Type1 = string | number; 890 | type Type2 = number | boolean; 891 | 892 | type Intersection = Type1 & Type2; // --> number 893 | ``` 894 | 895 | 896 | 897 | ## Type Guards 898 | 899 | ```typescript 900 | type Combinable = string | number; 901 | 902 | function add(a: Combinable, b: Combinable) { 903 | if (typeof a === 'string' || typeof b === 'string') { // this is a type guard 904 | return a.toString() + b.toString(); 905 | } 906 | 907 | return a + b; 908 | } 909 | ``` 910 | 911 | In case of combined types: 912 | 913 | ```typescript 914 | type Admin = { 915 | name: string; 916 | priviliges: string[]; 917 | }; 918 | 919 | type Employee = { 920 | name: string; 921 | startDate: Date; 922 | }; 923 | 924 | type UnknownEmp = Admin | Employee; // admin OR employee 925 | 926 | function printEmpInfo(emp: UnknownEmp) { 927 | console.log(emp.name); 928 | if ('priviliges' in emp) { // type guard 929 | console.log(emp.priviliges); 930 | } 931 | } 932 | ``` 933 | 934 | Or we could use `instanceof` as a type guard. 935 | 936 | 937 | 938 | ## Discriminated Unions 939 | 940 | ```typescript 941 | interface Bird { 942 | type: 'bird'; // literal type 943 | flyingSpeed: number; 944 | } 945 | 946 | interface Horse { 947 | type: 'horse'; 948 | runningSpeed: number; 949 | } 950 | 951 | type Animal = Bird | Horse; 952 | 953 | function moveAnimal(animal: Animal) { 954 | let speed; 955 | switch (animal.type) { 956 | case 'bird': 957 | speed = animal.flyingSpeed; 958 | case 'horse': 959 | speed = animal.runningSpeed; 960 | } 961 | 962 | console.log("Moving at speed: ", speed); 963 | } 964 | ``` 965 | 966 | 967 | 968 | ## Type Casting 969 | 970 | We basically specify the type of something, useful especially when manipulating the DOM: 971 | 972 | ```typescript 973 | const inputEl = document.getElementById('user-input')!; // ! means that we tell TS not to worry about the fact that maybe inputEl doesn't exist. 974 | 975 | inputEl.value = "Hi there!"; // we can safely access value because we are telling TS that inputEl is going to be HTMLInputElement, otherwise it complains about the fact that the value property may not exist. 976 | ``` 977 | 978 | But this uses the same syntax as some React stuff (I don't know React I use Vue xD) so in that case we use the `as` keyword: 979 | 980 | ```typescript 981 | const inputEl = document.getElementById('user-input')! as HTMLInputElement; 982 | ``` 983 | 984 | 985 | 986 | ## Index Properties 987 | 988 | We use them to build flexible interfaces. 989 | 990 | ```typescript 991 | interface ErrorCOntainer { // flexible container 992 | [prop: string]: string; // every property we add must be a string, it is like a 'general keyword' 993 | id: string; // OK 994 | code: number; // NO 995 | } 996 | ``` 997 | 998 | We specify that properties names and their values must be strings BUT we don't actually know the properties. 999 | 1000 | 1001 | 1002 | ## Function Overloads 1003 | 1004 | ```typescript 1005 | type Combinable = string | number; 1006 | 1007 | function add(a: number, b: number): number; // if both params are number then return a number 1008 | function add(a: Combinable, b: Combinable) { 1009 | if (typeof a === 'string' || typeof b === 'string') { // this is a type guard 1010 | return a.toString() + b.toString(); 1011 | } 1012 | 1013 | return a + b; 1014 | } 1015 | ``` 1016 | 1017 | It is similar to an if statement but related to function params. It gets 'translated' to: if we call the function 'add' with two numbers then expect back a number. So later in the code we can handle the result as a number (we can use numbers related methods without warnings). 1018 | 1019 | 1020 | 1021 | ## Optional Chaining 1022 | 1023 | Useful when we fetch data from an API and we don't know if the result as some properties. 1024 | 1025 | ```typescript 1026 | const fetchedData = { 1027 | id: 'u1', 1028 | name: 'Leo', 1029 | // job: {title: 'CEO', payCheck: 10000} ---> imagine that this doesn't get fetched correctly 1030 | }; 1031 | 1032 | console.log(fetchedData.job.title) // ERROR 1033 | ``` 1034 | 1035 | We can solve this by adding a `?` to the object 1036 | 1037 | ```typescript 1038 | console.log(fetchedData.job?.title) // ERROR 1039 | ``` 1040 | 1041 | 1042 | 1043 | ## Nullish Coalescing 1044 | 1045 | If we don't know if a piece of data is `null` we can do: 1046 | 1047 | ```typescript 1048 | const gotData = null; // data that we don't know if it is NULL 1049 | 1050 | const storedData = gotData || 'Default'; // JS 1051 | const storedData = gotData ?? 'Default'; // TS --> ONLY IF gotData is null or undefined 1052 | ``` 1053 | 1054 | 1055 | 1056 | # Generics 1057 | 1058 | They don't exist in JavaScript but the concept of Generic Types exist in other programming languages. 1059 | 1060 | An array is actually a `generic`. 1061 | 1062 | ## What are generics? 1063 | 1064 | ``Array`` 1065 | 1066 | A generic type is a type which is kinda connected with some other types and is really flexible in terms of what type the other type is. 1067 | 1068 | The `Array` type doesn't really care about what data you store in it. 1069 | 1070 | ```typescript 1071 | const names: Array = []; // same thing as string[] 1072 | ``` 1073 | 1074 | 1075 | 1076 | Another generic type is `Promise`. 1077 | 1078 | ```typescript 1079 | const promise = new Promise((resolve, reject) => { 1080 | setTimeout(() => { 1081 | resolve('Done'); 1082 | }, 1000) 1083 | }); 1084 | ``` 1085 | 1086 | Here the type of the promise is `Promise` because it will eventually resolve into something. 1087 | 1088 | So we can say: 1089 | 1090 | ```typescript 1091 | const promise: Promise = new Promise((resolve, reject) => { 1092 | setTimeout(() => { 1093 | resolve('Done'); 1094 | }, 1000) 1095 | }); 1096 | ``` 1097 | 1098 | We specify that the promise eventually resolves into a `string`. 1099 | 1100 | Generic types gives us more safety. 1101 | 1102 | 1103 | 1104 | ## Custom Generic 1105 | 1106 | ### Functions 1107 | 1108 | ```typescript 1109 | function merge(objA: object, objB: object) { 1110 | return Object.assign(objA, objB); 1111 | } 1112 | 1113 | const merged = merge({name: 'Leo'}, {age: 17}); 1114 | merged.age; // TS ERROR, typescript doesn't know the properties (we could do TYPE CASTING or GENERIC TYPES) 1115 | ``` 1116 | 1117 | ```typescript 1118 | function merge(objA: T, objB: U) { //T and U are cusotm identifiers 1119 | return Object.assign(objA, objB); 1120 | } 1121 | 1122 | // THIS FUNCTION RETURNS THE INTERSECTION OF T AND U 1123 | const merged = merge({name: 'Leo'}, {age: 17}); // name: string & age: number 1124 | ``` 1125 | 1126 | They are used to specify that what we store in the result is the intersection between the parameters (we actually don't know what they are 'made of'). 1127 | 1128 | We can also specify what parameters we are passing: 1129 | 1130 | ```typescript 1131 | const merged = merge<{name: string}, {age: number}>({name: 'Leo'}, {age: 17}); 1132 | ``` 1133 | 1134 | **But this is redundant.** 1135 | 1136 | 1137 | 1138 | ### Constraints 1139 | 1140 | Sometimes we want to **restrict** the types of generic types. 1141 | 1142 | ```typescript 1143 | function merge(objA: T, objB: U) { //T and U are cusotm identifiers 1144 | return Object.assign(objA, objB); 1145 | } 1146 | ``` 1147 | 1148 | So we have improved the merge function by reducing unwanted behaviors such as passing just a number to the `merge` function. 1149 | 1150 | We can also improve this by creating custom `interfaces` and using them with `extends ...` if we only care about certain params properties. 1151 | 1152 | 1153 | 1154 | #### KeyOf Constraint 1155 | 1156 | ```typescript 1157 | function extractAndConvert(obj: object, key: string) { 1158 | return obj[key]; // TS ERROR since we don't know if the object has the key property 1159 | } 1160 | ``` 1161 | 1162 | We can fix this by using `generics` 1163 | 1164 | ```typescript 1165 | function extractAndConvert(obj: T, key: U) { 1166 | return obj[key]; // OK 1167 | } 1168 | ``` 1169 | 1170 | 1171 | 1172 | ## Generic Classes 1173 | 1174 | ```typescript 1175 | class DataStorage { 1176 | private data: T[] = []; 1177 | 1178 | addItem(item: T) { 1179 | this.data.push(item); 1180 | } 1181 | 1182 | removeItem(item: T) { 1183 | if (this.data.indexOf(item) !== -1) this.data.splice(this.data.indexOf(item), 1); 1184 | } 1185 | 1186 | getItems() { 1187 | return [...this.data]; 1188 | } 1189 | } 1190 | 1191 | const textStorage = new DataStorage(); 1192 | const numberStorage = new DataStorage(); 1193 | ``` 1194 | 1195 | 1196 | 1197 | ## Generic Utility Types 1198 | 1199 | Special Utility Types. 1200 | 1201 | #### Partial 1202 | 1203 | ```typescript 1204 | interface Article { 1205 | title: string; 1206 | description: string; 1207 | } 1208 | 1209 | function createArticle(title: string, description: string): Article { 1210 | const toServe: Partial
= {}; // This is an object that in the **end** will be an Article 1211 | 1212 | // building manually, maybe we have to do some filtering 1213 | toServe.title = title; 1214 | toServe.decription = description; 1215 | 1216 | return toServe as Article; 1217 | } 1218 | ``` 1219 | 1220 | 1221 | 1222 | ### Readonly 1223 | 1224 | ```typescript 1225 | const names: Readonly = ['Leo', 'Anna']; 1226 | ``` 1227 | 1228 | 1229 | 1230 | ## Generic vs Union Types? 1231 | 1232 | ```typescript 1233 | class DataStorage { 1234 | private data: T[] = []; 1235 | 1236 | addItem(item: T) { 1237 | this.data.push(item); 1238 | } 1239 | 1240 | removeItem(item: T) { 1241 | if (this.data.indexOf(item) !== -1) this.data.splice(this.data.indexOf(item), 1); 1242 | } 1243 | 1244 | getItems() { 1245 | return [...this.data]; 1246 | } 1247 | } 1248 | ``` 1249 | 1250 | ```typescript 1251 | class DataStorage { 1252 | private data: (string | number | boolean)[] = []; 1253 | 1254 | addItem(item: string | number | boolean) { 1255 | this.data.push(item); 1256 | } 1257 | 1258 | removeItem(item: string | number | boolean) { 1259 | if (this.data.indexOf(item) !== -1) this.data.splice(this.data.indexOf(item), 1); 1260 | } 1261 | 1262 | getItems() { 1263 | return [...this.data]; 1264 | } 1265 | } 1266 | ``` 1267 | 1268 | In the second example we allow **mixed** types, to fix that we would have to do ``string[] | number[] | boolean[]`` BUT then we would have a problem while adding and removing stuff because with union types we allow some types every time we call that specific action. 1269 | 1270 | So generic types makes us choose a type of data every time from a range of types, it doesn't accept mixed stuff. 1271 | 1272 | In order words generics locks in a specific type. 1273 | 1274 | 1275 | 1276 | # Decorators 1277 | 1278 | ## DISCLAIMER 1279 | 1280 | Decorators are much more in depth than how they are described in this chapter so more knowledge [here](More [here](https://www.typescriptlang.org/docs/handbook/decorators.html)). 1281 | 1282 | 1283 | 1284 | Writing code that's easier to use for developers. 1285 | 1286 | Decorators are usually about classes and they are **functions**. 1287 | 1288 | **MUST USE WITH ES6 AND EXPERIMENTAL-DECORATORS in TSCONFIG.JSON** 1289 | 1290 | 1291 | 1292 | ```typescript 1293 | function Logger(constructor: Function) { // decorators expect arguments 1294 | console.log("Logging"); 1295 | console.log(constructor); 1296 | } 1297 | 1298 | @Logger 1299 | class Person { 1300 | name: 'Leo'; 1301 | 1302 | constructor() { 1303 | console.log("Creating person..."); 1304 | } 1305 | } 1306 | ``` 1307 | 1308 | They run without an instance, so they execute when you define a class. 1309 | 1310 | 1311 | 1312 | ## Decorators Factories 1313 | 1314 | They create decorators that we can configure. 1315 | 1316 | ```typescript 1317 | function Logger(logString: string) { 1318 | return function(constructor: Function) { 1319 | console.log(logString); 1320 | console.log(constructor); 1321 | } 1322 | } 1323 | 1324 | @Logger('LOGGING-PERSON') 1325 | class Person { 1326 | name: 'Leo'; 1327 | 1328 | constructor() { 1329 | console.log("Creating person..."); 1330 | } 1331 | } 1332 | ``` 1333 | 1334 | 1335 | 1336 | ## Example 1337 | 1338 | ```typescript 1339 | function WithTemplate(template: string, hookId: string) { 1340 | return function(_: Function) { // we could pass a class constructor 1341 | const hookEl = document.getElementById(hookId); 1342 | if (hookEl) { 1343 | hookEl.innerHTML = template; 1344 | } 1345 | } 1346 | } 1347 | 1348 | @WithTemplate('

Lorem Ipsum

', 'app'); // app is an ID on a DIV 1349 | ``` 1350 | 1351 | This is like an Angular Decorator. 1352 | 1353 | We can also have multiple decorators per class and they execute from the bottom to the top. 1354 | 1355 | 1356 | 1357 | ## Property Decorators 1358 | 1359 | ```typescript 1360 | function Log(target: any, propertyName: string | Symbol) { 1361 | console.log(target, propertyName); 1362 | } 1363 | 1364 | class Product { 1365 | @Log 1366 | title: string; 1367 | 1368 | constructor(t: string) { 1369 | this.title = t; 1370 | } 1371 | 1372 | } 1373 | ``` 1374 | 1375 | **We can also create decorators for methods and accessors**. 1376 | 1377 | ## Returning in a decorator 1378 | 1379 | When can also return stuff in decorators, especially we can return classes. 1380 | 1381 | 1382 | 1383 | NOTE: this will decorate a class with a ``name`` property 1384 | 1385 | ```typescript 1386 | function WithTemplate(template: string, hookId: string) { 1387 | return function(original_constructor: T) { 1388 | return class extends original_constructor { // based on the og constructor 1389 | // adding new functionalities to the decorated class, this runs when the class is instantiated 1390 | constructor(..._: any[]) { 1391 | super(); 1392 | const hookEl = document.getElementById(hookId); 1393 | if (hookEl) { 1394 | hookEl.innerHTML = this.name; 1395 | } 1396 | } 1397 | } 1398 | } 1399 | } 1400 | ``` 1401 | 1402 | This basically replace the class that it decorated by keeping its original values. 1403 | 1404 | We can also return in method decorators. 1405 | 1406 | 1407 | 1408 | # Modules 1409 | 1410 | ## Namespaces and File Bundling 1411 | 1412 | Use "namespace" code syntax to group code. Bundled compilation is possible. 1413 | 1414 | In a specific file (``fileName.ts``) 1415 | 1416 | ```typescript 1417 | namespace AModule { 1418 | // code here 1419 | export interface numberOne {} 1420 | export interface numberTwo {} 1421 | } 1422 | ``` 1423 | 1424 | And we import it as follows: 1425 | 1426 | ```typescript 1427 | /// 1428 | ``` 1429 | 1430 | **But we can't access the single interfaces without putting the "main code" into a namespace with the same name as the exported one.** 1431 | 1432 | 1433 | 1434 | ### Result 1435 | 1436 | We get back multiple files but **they aren't linked between each other**. In order to link them we have to set the ``outFile`` option in `tsconfig` which bundles everything in one file and we also need to set the `module` option to `amd`. 1437 | 1438 | ## ES6 Modules 1439 | 1440 | Modern JavaScript uses ES6 Imports/Exports. TypeScript also supports this. Bundling via third-party tools is possible. 1441 | 1442 | ### Syntax 1443 | 1444 | ```typescript 1445 | import defModule from './path/file.js' 1446 | import { module } from './path/another.js' 1447 | ``` 1448 | 1449 | As long as we don't use a ``webpack`` make sure to add `.js` even if we are developing in TypeScript or just omit the extension (this can cause some errors depending on you environment). 1450 | 1451 | 1452 | 1453 | We can obviously use ``default`` exports and other features. 1454 | 1455 | ### tsconfig 1456 | 1457 | We need to set these flags in the ``tsconfig.json`` 1458 | 1459 | ``` 1460 | target: es6 (or higher) 1461 | module: es2015 (or higher) 1462 | ``` 1463 | 1464 | We can't use the `outfile` flag. 1465 | 1466 | ### IMPORTANT 1467 | 1468 | In a HTML file we have to add the `module` flag. 1469 | 1470 | ```html 1471 | 1472 | ``` 1473 | 1474 | Modules get executed the first time they get imported in the app even though we import a single one multiple times in different files. 1475 | 1476 | 1477 | 1478 | # Webpack 1479 | 1480 | ## What is Webpack? 1481 | 1482 | Splitting code in multiple modules result in a lot of ``http requests``. 1483 | 1484 | Webpack is a tool to bundle files together (Build Orchestration Tool). 1485 | 1486 | It also optimizes our code (minimized code, less imports, etc). 1487 | 1488 | ## Install 1489 | 1490 | ``` 1491 | npm install --save-dev webpack webpack-cli webpack-dev-server typescript ts-loader 1492 | ``` 1493 | 1494 | **Installing a copy of `typescript` in every project is a good practice in order not to break an existing project if typescript gets updated with deep new features.** 1495 | 1496 | ## Configurations 1497 | 1498 | In `tsconfig.json` 1499 | 1500 | ``` 1501 | target: es5/es6/esnext 1502 | module: es2015/es6 1503 | NO rootDir 1504 | sourceMap: true --> helps debugging 1505 | ``` 1506 | 1507 | ``webpack.config.js`` 1508 | 1509 | ```javascript 1510 | const path = require('path'); 1511 | 1512 | module.exports = { 1513 | entry: './src/apps.ts', // root project entry 1514 | output: { 1515 | filename: 'bundle.js' // out file 1516 | path: path.resolve(__dirname, 'dist') // absolute path (same as the on ein tsconfig) 1517 | }, 1518 | devtool: 'inline-source-map', // alreay generated source maps (tsconfig) 1519 | // instructions on how to deal ts files 1520 | module: { 1521 | rules: [ 1522 | { 1523 | test: /\.ts$/, 1524 | use: 'ts-loader', 1525 | exclude: /node_modules/ 1526 | } 1527 | ] 1528 | }, 1529 | 1530 | resolve: { 1531 | extensions: ['.ts', '.js'] 1532 | } 1533 | }; 1534 | ``` 1535 | 1536 | REMOVE ALL EXTENSIONS IN IMPORT STATEMENTS 1537 | 1538 | ## How to use Webpack 1539 | 1540 | in ``package.json`` 1541 | 1542 | ```json 1543 | "build" : "webpack" 1544 | ``` 1545 | 1546 | And then we can use the generated file. 1547 | 1548 | ## Dev Workflow 1549 | 1550 | in `package.json` 1551 | 1552 | ```json 1553 | "dev" : "webpack-dev-server" 1554 | ``` 1555 | 1556 | **In dev mode the bundle is generated in memory only** 1557 | 1558 | So we need to add (in `webpack.config.js`): 1559 | 1560 | ```js 1561 | mode: 'development' // fewer optimizations 1562 | publicPath: 'dist' 1563 | ``` 1564 | 1565 | ## Production Workflow 1566 | 1567 | ### Useful Requirements 1568 | 1569 | ``` 1570 | npm i --save-dev clean-webpack-plugin 1571 | ``` 1572 | 1573 | To clear the bundle every time we have a new version. 1574 | 1575 | ``webpack.config.prod.js`` 1576 | 1577 | ```javascript 1578 | const path = require('path'); 1579 | const CleanPlugin = require('clean-webpack-plugin'); 1580 | 1581 | module.exports = { 1582 | mode: 'production', 1583 | entry: './src/apps.ts', // root project entry 1584 | output: { 1585 | filename: 'bundle.js' // out file 1586 | path: path.resolve(__dirname, 'dist') // absolute path (same as the on ein tsconfig) 1587 | }, 1588 | devtool: 'none', // alreay generated source maps (tsconfig) 1589 | // instructions on how to deal ts files 1590 | module: { 1591 | rules: [ 1592 | { 1593 | test: /\.ts$/, 1594 | use: 'ts-loader', 1595 | exclude: /node_modules/ 1596 | } 1597 | ] 1598 | }, 1599 | 1600 | resolve: { 1601 | extensions: ['.ts', '.js'] 1602 | }, 1603 | plugins: [ 1604 | new CleanPlugin.CleanWebpackPlugin() 1605 | ] 1606 | }; 1607 | ``` 1608 | 1609 | 1610 | 1611 | ``package.json`` 1612 | 1613 | ```json 1614 | "build" : "webpack --config webpack.config.prod.js" 1615 | ``` 1616 | 1617 | 1618 | 1619 | # NodeJS and Express 1620 | 1621 | Node is not able to run `TypeScript` files. We could install ``ts-node`` but it is not good for production. 1622 | 1623 | What we can do is: 1624 | 1625 | * npm init 1626 | * tsc --init 1627 | * `target: esnext` 1628 | * `moduleResolution: node` 1629 | * npm i express 1630 | * npm i --save-dev nodemon 1631 | * npm i --save-dev @types/node 1632 | * npm i --save-dev @types/express 1633 | 1634 | ## Useful stuff 1635 | 1636 | ```typescript 1637 | import { RequestHandler } from 'express'; 1638 | 1639 | export const controller: RequestHandler = (req, res, next) => {} 1640 | ``` 1641 | 1642 | 1643 | 1644 | ```typescript 1645 | import { Request, Response, NextFunction } from 'express'; 1646 | ``` 1647 | 1648 | 1649 | 1650 | 1651 | 1652 | # Credits 1653 | 1654 | Extended cheatsheet made by Leonardo Folgon and made by following various resources on the internet. 1655 | -------------------------------------------------------------------------------- /cheatsheet/ts.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/ts-extended-cheatsheet/e66c1aaea0558b77d4246f81348aa2e2d94cd63b/cheatsheet/ts.pdf --------------------------------------------------------------------------------