JS 6 - Getting started with TypeScript

By Sheldon L Published at 2020-03-05 Updated at 2020-03-05


TypeScript Basics

Compiler & Configuration Deep Dive

Installation

Project setup

<head>
  <script src="app.js" defer></script>
</head>
mkdir src
mkdir dist

tsc init    # `tsconfig.json`
# "exclude": ["node_modules", "**/*.dev.ts"]
# "include": ["app.ts"]
# "target": "es6" or as you want
# "outDir": "./dist"
# "rootDir": "./src"
# "noEmitOnError": true,

tsc app.ts

npm init -y
npm install --save-dav lite-server
{
  "scripts": {
    "start": "lite-server"
  }
}

Working with Next-gen JS Code

Core Types

// Types matters

const button = document.querySelector('button');
const input1 = document.getElementById('num1')! as HTMLInputElement;
const input2 = document.getElementById('num2')! as HTMLInputElement;

function addInputs(num1: number, num2: number) {
  return num1 + num2;
}

button.addEventListener("click", function() {
  console.log(addInputs(+input1.value, +input2.value))
});


// Number, string, boolean

// function add(n1, n2, showResult, resultPhrase)

function add(n1:number, n2:number, showResult:boolean, resultPhrase:string) {

  const result = n1 + n2;
  if (showResult) {
    console.log(resultPhrase + result);
  } else {
    return result;
  }
}

const n1 = '5';
const n2 = 2.8;
const showResult = true;
const resultPhrase = 'Result is: '

add(+n1, +n2, showResult, resultPhrase)


// ================================================


// Object, array and tuple

// const person = {
const person: {
  name: string;
  age: number;
  hobbies: string[];
  role: [number, string];
} = {
  name: 'Maximilian',
  age: 30,
  hobbies: ['Sports', 'Cooking'],  // array
  role: [2, 'author']              // tuple
};

person.role.push('admin'); // will be allowed as a tuple
// person.role[1] = 10;       // will not be allowed as a tuple
// person.role = [0, 'admin', 'user']   // will not be allowed as a tuple

let favoriteActivities: string[];
favoriteActivities = ['Sports'];

console.log(person.name)

for (const hobby of person.hobbies) {
  console.log(hobby.toUpperCase())
}

console.log(person.role)

//===================================================


// Enum

// //           0      1          2         // default
// enum Role { ADMIN, READ_ONLY, AUTHOR };  // often, all-uppercase
// // defined to num or string
// enum Role { ADMIN = 10, READ_ONLY = 100, AUTHOR = 1000};  
enum Role { ADMIN = 'Admin', READ_ONLY = 'Read only', AUTHOR = 'Author'};

const person = {
  name: 'John',
  age: 30,
  hobbies: ['Sports', 'Cooking'],
  role: Role.AUTHOR
}

if (person.role === Role.AUTHOR) {
  console.log('is author')
}

// ==========================================

Advanced Types

// Union types, literal types, alian types

type Addable = number | string;                     // alian + union
type ConversionDescriptor = 'as_number' | 'as_text' // alian + union + literal

function add(
  n1: Addable,                         // alian
  n2: number | string,                 // union
  // resultType: string
  resultType: ConversionDescriptor     // alian
) {
  let result;
  if (typeof n1 === 'number' && typeof n2 === 'number' || resultType === 'as_number'){
    result = +n1 + +n2;
  } else {
    result = n1.toString() + n2.toString();
  }

  // if (resultType === 'as_number') {
  //     return +result;
  // } else {
  //     return result.toString;
  // }

  return result
}

console.log(add(30, 26, 'as_number'))
console.log(add('30', '26', 'as_text'))
console.log(add('Anna', 'Bill', 'as_text'))

// ==================================


// Function, function var, call back

function add2(n1: number, n2: number) {
  return n1 + n2
}

function printResult(num: number): void {
  console.log('Result: ' + num)
}                                      // void, no return value

function printResult2(num: number): undefined {
  console.log('Result: ' + num)
  return;                            // same as above, rarelly used
}

printResult(add2(6, 9));
console.log(printResult(add2(6, 9)))    // print 'undefined'


// Function Var

// let value;              // default type: any
// let value: Function;    // better
// let value: () => number;   // much better
let value: (a: number, b: number) => number; // much much better

value = add2;  // store add function to var value

console.log(value(8, 8))


// Call back function

function addAndHandle(
  n1: number,
  n2: number,
  callBack: (num: number) => void
) {
  const result = n1 + n2;
  callBack(result)
}

addAndHandle(10, 20, (result) => {
  console.log(result);
})

// ===============================================


// Unknown and Never

// Unknown
let userName: string;
let userInput: unknown;               // unkown is more strict than any, is better than any
let userWhat: any;

userInput = 5;
userInput = 'Max'

// userName = userInput               // string not allow unknown
userName = userWhat                   // string allow any
if (typeof userInput === 'string') {
  userName = userInput              // string allow checked unknown
}


// Never

function generateError(
  message: string,
  code: number,
): never {                     // never return, will disrupt our scripts
  throw { message: message, errorCode: code };
}

generateError('An error occurred!', 1);

Compiler

tsc --init      # create config file
tsc app.ts      # compile app.ts

tsc             # compile rootDir .ts in `"include": []` in `tsconfig.json`
                # or compile rootDir .ts except file listed in `"exclude": []`

tsc --watch|-w  # recompile whenver saved