100-123


(103) Types inferred type

var a = 'hello' // inferred string

explicit type

var a:string = 'hello' // explicit string


var arr: string[] = []
arr.push('hello') // ok
arr.push(123) // nok

ANY - last resort

var a:any = 'hello'
a = 3; //ok
a = true //ok

(104) User defined types objects have types functions have types

interface

interface Person {
firstName: string,
lastName: string,
}

type

type job = string

type specificJob = 'Engineer' | 'Programmer'

combining types > found in AWS sdk

type AWSError = Error & {
code: string;
}

(105) Optional properties optional properties

interface Foo {
optProp?: string // optional
}

optional parameters

function foo(optParam?: string) {}

(106) Type guards type info only exists at compile time runtime is not checked -> type guards

function isPerson(potentialPerson: any): boolean {
return 'firstName' in potentialPerson && 'lastName' in potentialPerson
}

if(isPerson(foo)) {
const definitelyPerson: Person = foo
}

ref: Typescript: Type Guards


(109) Access Modifiers public // default private protected // -> classes who extend

workaround for private

const privateData = (someClass as any).somePrivateField

shorthand fields:

class Server {
private port: number
constructor(port: number) {this.port = port}
}

class SameServer {
constructor(private port: number) {this.port = port}
}

(110) Inheritance

abstract class BaseServer {
abstract stopServer(): void
}



class Server extends BaseServer {
stopServer(){}
}

(111) Implementing interfaces+

interface IServer {
startServer(): void
}

class Server implements IServer {
startServer(){}
}

(112) Generics

function returnKeys<T>(arg: T) {
return arg
}

function returnKeys<T extends Object>(arg: T) {
return arg
}

interface Person<T> {
special: T
}

(114) Modules

import {Bar} from './foo'
import * as Foo from './foo'

using paths without paths

import { Foo } from './data/components/Foo'

with paths

import { Foo } from '@components/Foo'

tsconfig.json (convention is to start with ‘@’)

{
"paths": {
"@components/*": ["data/components/*"]
}
}

(115) Strict Checks tsconfig.json

{
"compilerOptions": {
"noImplicitAny": true, // type must be configured
"noImplicitThis": true, // avoid errors within an anonymous function
"strictNullChecks": true, // forces 'string | undefined' to be unwrapped
"strictPropertyInitialization": true // require class field to be initialized
"strict": true // all other checks
}
}

(116) undefined, null, never, unknown

you often use undefined and null
you rarely use never and unknown

undefined & null are the same as in JS

Undefined constants - when it should be defined in the future

let abc = undefined

Undefined functions response - when remote call fails

function getDataOverInternet(): string | undefined {}

const data = getDataOverInternet()

if(data)
const definitelyString: string = data
else
throw new Error('nope')

Null - ?? don’t use it??

Unknown - when you’re not sure yet

let input: unknown;
input = someInput

if(typeof input === 'string')
const definitelyString: string = input
else
throw new Error('nope')

Never - when you throw

function foo(tasks: number) : void | never {
if(tasks > 3)
throw new Error('too many tasks')
}

function error() : never {
throw new Error()
}

?? why not void|Error -> that’s Promises / callbacks, Error is not a return type of a direct throw (unless wrapped in Promise / callback)


(117) Enums and Switch

enum Foo { A,B,C }

Foo.A // = 0
Foo[Foo.A] // = "A"

enum Bar {
A = "aaa",
B = "bbb",
C = "ccc"
}
Foo.A // = "aaa"
const foo: Foo = Foo.A
switch(foo) {
case Foo.A:
break;
case Foo.B:
case Foo.C:
break;
default:
break;
}

(118) Running on NodeJS

npm i -D @types/node

// Server.ts

import { createServer, IncomingMessage, ServerResponse } from 'http'


export class Server {
public startServer(){
createServer(
(req: IncomingMessage, res: ServerResponse)=>{
console.log(`Got request from ${req.headers['user-agent']} for ${req.url}`)
res.write('Hello from TS server!')
res.end()
}
).listen(8080)
console.log('Server started')
}
}

// Launcher.ts

import { Server } from "./Server";


class Launcher {
private server: Server = new Server();


public launchApp(){
this.server.startServer()
}
}

new Launcher().launchApp()

running with node

tsc
node dist/Launcher.js

running with ts-node

npm i -D ts-node
npm i -D typescript

ts-node src/Launcher.ts

(119) Debugging Node Typescript

run config (in VSCode)

{
"version": "0.2.0",
"configurations":[
{
"type": "node"
"request": "launch"
"name":"Debug local file",
"runtimeArgs":["-r", "ts-node/register"]
"args":"${relativeFile}"
"env":{"AWS_REGION":"eu-west-2"}
}
]
}

(you can add AWS credentials to env if you’re not logged in locally)


(120) Running in the browser

vscode plugin ‘Live Server’ ./.vscode/settings.json

{
"liveServer.settings.file": "index.html"
}

typescript compile alias cmd for tsc NGINX: single page application static website (nginx docker)

Webpack

npm i -D typescript ts-node ts-loader
npm i -D webpack webpack-cli @types/webpack

./webpack.config.ts

import {Configuration} from "webpack";
import {resolve} from "path"



const config: Configuration = {
entry: './src/Launcher.ts',
mode: 'development',
devtool: 'inline-source-map',
module: {
rules: [
{
use: 'ts-loader',
exclude: /node-_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: 'bundle.js',
path: resolve(__dirname, 'dist')
}
}



export default config

(122) Property Decorators https://www.typescriptlang.org/docs/handbook/decorators.html add something to existing classes / method / accessor / property / parameter tsconfig.json

{
"compilerOptions": {
"experimentalDecorators": true
}
}

Class properties

class Manager {
@propertyDecorator
someProperty: string
}

new Manager().someProperty = 'foo'
// same as without the decorator calling:
propertyDecorator(Manager.prototype, 'someProperty')
function propertyDecorator(target: any, key: string) {
let property = target[key]
const getter = () => property
const getter = (newVal: any) => {property = newVal}
Object.defineProperty(target, key, {
get: getter,
set: setter,
configurable: true,
enumerable: true,
})
}

Decorator factory (second order function to pass config)

class Manager {
@decoratorWithParameters('foo')
someProperty: string
}

function decoratorWithParameters(otherObject:any) {
return (target: any, key: string) => ...
}

(123) Method decorators https://www.typescriptlang.org/docs/handbook/decorators.html tsconfig.json

{
"compilerOptions": {
"experimentalDecorators": true
}
}

Class properties

class Manager {
@methodDecorator
someMethod(){}
}
function methodDecorator(target: Object, propertyKey: string, descriptor: PropertyDecorator){
const classname = target.constructor.name
const originalMethod = descriptor.value
descriptor.value = async function(...args: any[]){
const result = await originalMethod.apply(this, args)
return result
}
}