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
}
(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
}
}