Skip to content

Instantly share code, notes, and snippets.

@pravdomil
Last active March 13, 2020 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pravdomil/fe7d0233f475556e98f1ca963344ea8c to your computer and use it in GitHub Desktop.
Save pravdomil/fe7d0233f475556e98f1ca963344ea8c to your computer and use it in GitHub Desktop.
Learn all TypeScript features in 10 + 3min

Learn TypeScript

https://youtu.be/ctS2v9IBphs

//// What is TypeScript?
// ts is super set of js
// + types
// + typecheck
// + transpiler(like babel)
// + many more




//// Setup TypeScript compiler
// npm i typescript -g   # install typescript compiller
// tsc file.ts           # compile files file.ts to file.js
// tsc init              # crate package.json
// tsc -p .              # run using package.json in cwd
// tsc -p . -w           # watch mode

// use "strict": true





//// JavaScript
// two types of values
// primitives: string, number, boolean, undefined
// references: function, object

// note: class is function and class instance is object
// note: null is also object

// typescript adds: enum, type, interface
// and many more: is, in, keyof, any, never, void...







//// Variable Type Declaration
// variableName colon variableType
() => {
  // declare by type
  let trueFalse: boolean
  let bar: number
  let text: string
  
  let myArray: string[] = ["foo"]
  let tuple: [string, number, boolean] = ["bar", 1, false]
  
  function bas(myNumber: number): void {

  }
  
  // declare by value
  let active = false
  let array = [0, 1, "string"]
  
  // any
  let anyValue: any = 123 // don't use it
  
  // Type assertions
  let myValue = 1 as any as string // don't use it
}








//// ES6+ is here
() => {
  // array destructuring
  let [first, second] = [1, 2]
  let [one, ...rest] = [1, 2, 3, 4]
  let [, two, , four] = [1, 2, 3, 4]
  
  // object destructuring
  let { a, b } = { a: 1, b: 2 }
  let { c, ...passthrough } = { c: 1, d: 2 }
  let { a: newName1, b: newName2 } = { a: 1, b: 2 }
  let { e, f: newName3 = "a" } = { e: 1 };  
  
  // variable swap
  [first, second] = [second, first]
  
  // array spread
  let firstArray = [1, 2]
  let secondArray = [3, 4]
  let bothPlus = [0, ...firstArray, ...secondArray, 5]
  
  // object spread
  let defaults = { a: 1 }
  let entered = { a: 2 }
  let search = { ...defaults, ...entered }
  
  // overkill
  function f({ a, b = 0 } = { a: "" }): { a: 1 } | void {
    // ...
  }
  
  
  // more at
  // http://es6-features.org
}







//// Declaration spaces
// Value X Type X Namespace
() => {
  // class creates type and value
  class MyClass {
    
  }
  let instance: MyClass = new MyClass()
  
  
  
  // enum creates type and value
  enum MyEnum {
    value = 0
  }
  let value: MyEnum = MyEnum.value
  
  
  
  // interface creates only type
  // global scope
  interface MyInterface {
    
  }
  // let myInterface: MyInterface = MyInterface // error
  
  
  
  // type creates only type
  type MyType = {
    
  }
  // let myType: MyType = MyType // error
  
  
  
  // function creates only value
  function myFunction() {
    
  }
  // let foo: myFunction = myFunction // error
  
  
  
  // value creates only value
  let myNumber = 123
  // let foo: myNumber = myNumber // error
  
  // convert value to type
  let myNextVariable: typeof myNumber
  
  // remember: only class, enum, interface, type creates types
}







//// Types
() => {
  // String Literal Types
  function bar(color: "green" | "red") {
    // color = "white" // error
  }
  
  interface SomeInterface {
    // Class Constructor Type
    new(foo: number, bar: number): SomeInterface
    
    // Function Type
    replace(heystack: string, needle: string): string
    
    // Index Type
    [index: number]: string
    
    // this Type
    returnInstance(): this
  }
}







//// Functions
() => {
  // optional parameters
  // spread operator
  // optional return types
  // this type
  
  function foo(this: HTMLElement, arg?: number, ...rest: number[]): boolean {
    this.innerHTML
    return true
  }
  
  // anonymous
  // default value
  let anonymousFunc = (arg: number = 1): boolean => {
    return true
  }
}








//// Type alias
// creates type
() => {
  type trueFalseOrNothing = boolean | "nothing"
  let foo: trueFalseOrNothing = false
  
  type Circle = {
    radius: number,
  }
  let circle: Circle = { radius: 10 }
  
  // cannot be "extends"
}
// local scope
// let foo: trueFalseOrNothing // error








//// Interface
// creates type
// polutes entire file scope (or use namespaces)
// can be "extends"
interface Base {
  type: string
}

interface Human extends Base {
  type: "human"
  age: number
}

interface Animal extends Base {
  type: "animal"
  age: number
}

// later on I might need human's name
// declaration merging
// don't forget readonly and optional
interface Human extends Base {
  readonly name?: string
}

() => {
  function createHuman(): Human {
    return { type: "human", age: 1 } // add name
  }
  
  function updateHuman(human: Human) {
    human.age++
    // human.type = "worker" // error
  }
}
// global scope
let myAnimal: Animal







//// Enum
// similar to other languages
() => {
  // indexed members
  enum MyEnum {
    foo = 1,
    bar
  }
  
  // multiple values
  enum FileAccess {
    // constant members
    None,
    Read = 1 << 1,
    Write = 1 << 2,
    ReadWrite = Read | Write,
    // computed member
    G = "123".length
  }
  
  FileAccess.ReadWrite
  
  // string value
  enum MyEnumString {
    foo = "bar"
  }
}
// local scope
// MyEnumString.foo // error







//// Class
// can "extends" classes and "implements" types
// abstract classes
// you can define it's properties
// modifiers: public(anyone, default), private(current class), protected(current and childs)
// don't forget readonly and optional
// static variables and function
// constructor properties
() => {
  class Foo {
    
  }
  
  abstract class AnimalAbstract extends Foo implements Animal {
    type: "animal"
    age: number
  }
  // let animalAbstract = new AnimalAbstract() // error
  
  class Fish extends AnimalAbstract {
    private readonly color?: string
    
    static ocean = "Atlantic"
    
    constructor(public name: string) {
      super()
    }
    
    protected walk() {
      
    }
  }
  
  // super
  // get set
  class GoldFish extends Fish {
    walk() {
      super.walk()
    }
    
    get description() {
      return this.type + this.name
    }

    set birthDate(date: number) {
      this.age = new Date().getTime() - date
    }
  }
}
// local scope
// let myGoldFish: GoldFish









//// Union type |
// defines that value can have multiple types
() => {
  function bar(arg: string | number | HTMLElement) {
    arg
  }
  
  // used in optional arguments
  function foo(optionalArg?: string) {
    optionalArg
  }
}







//// Intersection Types &
// for extending properties
() => {
  type Loggable = { log(): void }
  
  type LoggableHuman = Human & Loggable
  
  let human = {} as LoggableHuman
  human
  
  // used in
  Object.assign
}







//// Type Guards
// ensures value type
() => {
  // using typeof
  function foo(optionalArg?: string | Function) {
    if(typeof optionalArg == "undefined") {
      optionalArg
      return
    }
    else if(typeof optionalArg == "function") {
      optionalArg
      return optionalArg
    }
    else {
      optionalArg
      return optionalArg
    }
  }
  
  // using instanceof
  function bar(arg: Event | HTMLElement) {
    if(arg instanceof HTMLElement) {
      arg
    }
    else {
      arg
    }
  }
  
  // using user defined type guard
  // check obj.type
  function isAnimal(obj: Human | Animal): obj is Animal {
    return obj.type == "animal"
  }
  
  // type never
  function myFunction(name: string) {
    if(typeof name == "string") {
      name
    }
    else {
      name
    }
  }
}





//// Namespaces
namespace Shapes {
  export namespace Polygons {
    export class Triangle { }
    export class Square { }
  }
}

new Shapes.Polygons.Triangle()

import polygons = Shapes.Polygons
let sq = new polygons.Square();




//// Generics
// you might need to pass types into functions and classes
() => {
  function loadAnimalFromServer(): Promise<Animal> {
    return new Promise((resolve) => { })
  }
  
  loadAnimalFromServer().then(animal => {
    
  })
  
  function createInstance<A extends Animal>(animalClass: new() => A): A {
    return new animalClass()
  }
}





//// Truthy
if("") { }        // false
if(NaN) { }       // false
if(undefined) { } // false
if(null) { }      // false

if({}) { }        // true
if([]) { }        // true

if(undefined == null) { } // true

if(false == "") { } // true
if(false == 0) { } // true
if(0 == "") { } // true

if(0 == null) { }         // ?





//// You don't need null
// use undefined instead
// https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#null-and-undefined




//// Modules
// same ES6 syntax
// import a from "b"
export let number = 1;
// you can import/export namespaces, types and values
// barrel: export * from "./elements/Spacer"





//// More tips
() => {
  // Make all properties in T optional
  let partial: Partial<Human> = { name: "Paul" }
  // see declaration
  
  // Make all properties in T readonly
  let readonly: Readonly<Human> = { type: "human", name: "Paul", age: 3 }
  // readonly.name = "me" // error
  // see declaration
  
  // Construct a type with a set of properties K of type T
  let record: Record<"hmm", Performance>
  // see declaration
  
  // learn about javascript call stack
  // https://www.youtube.com/watch?v=8aGhZQkoFbQ
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment