SlideShare a Scribd company logo
TypeScript
as a runtime error terminator
Dlaczego TypeScript?
?
?
?
?
?
?
?
Problemy z JSem
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]);
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]);
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]); // NaN
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]); // NaN
sum({ reduce: () => '😜' });
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]); // NaN
sum({ reduce: () => '😜' }); // "😜"
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]); // NaN
sum({ reduce: () => '😜' }); // "😜"
sum({});
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]); // NaN
sum({ reduce: () => '😜' }); // "😜"
sum({});
Problemy z JSem
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]); // NaN
sum({ reduce: () => '😜' }); // "😜"
sum({});
Problemy z JSem
Problemy języków dynamicznie typowanych
function sum(elements) {


return elements.reduce((a, b) => a + b, 0);


}
sum([1, 2, 3]); // 6
sum(["1", "2", "3"]); // "0123"
sum([undefined, 2, 3, 4]); // NaN
sum({ reduce: () => '😜' }); // "😜"
sum({});
Zaawansowane


👨🏫
Podstawowa ochrona typów
function sum(elements: number[]) {


return elements.reduce((a, b) => a + b, 0);


}
Typy złożone
type User = {


id: string;


firstName: string;


lastName: string;


email: string;


}


function createUser(user: User) {


// ...


}
Dziękuje za uwagę!
Dziękuje za uwagę! Pytania?
Dziękuje za uwagę! Pytania?
🐣 Podstawy
JSDoc?
👨🏫 Zaawansowany
Generyki


🤹
https://www.typescriptlang.org/docs/handbook/2/generics.html
function identity(arg: number): number {


return arg;


}
function identity(arg: number): number {


return arg;


}
const x = identity(5); // x: number
function identity(arg: number): number {


return arg;


}
const x = identity(5); // x: number
const y = identity("a");
function identity(arg: number): number {


return arg;


}
const x = identity(5); // x: number
const y = identity("a");
function identity(arg: any): any {


return arg;


}
function identity(arg: any): any {


return arg;


}
const x = identity(5);
function identity(arg: any): any {


return arg;


}
const x = identity(5);
const y = identity("a");
function identity(arg: any): any {


return arg;


}
const x = identity(5);
const y = identity("a");
// x: any
function identity(arg: any): any {


return arg;


}
const x = identity(5);
const y = identity("a");
// x: any
// y: any
function identity<Type>(arg: Type): Type {


return arg;


}
function identity<Type>(arg: Type): Type {


return arg;


}
const x = identity<number>(1); // x: number
function identity<Type>(arg: Type): Type {


return arg;


}
const x = identity<number>(1); // x: number
const y = identity<number>("1");
function identity<Type>(arg: Type): Type {


return arg;


}
const x = identity<number>(1); // x: number
const y = identity<number>("1");
function identity<Type>(arg: Type): Type {


return arg;


}
const x = identity<number>(1); // x: number
const y = identity<number>("1");
const z = identity<string>("1"); // z: string
Type inference


🕵
function identity<Type>(arg: Type): Type {


return arg;


}
const x = identity<number>(1); // x: number
const y = identity<string>("1"); // z: string
function identity<Type>(arg: Type): Type {


return arg;


}
const x = identity(1); // x: number
const y = identity("1"); // z: string
Utility Types


🛠
https://www.typescriptlang.org/docs/handbook/utility-types.html
Case study: User update
DEMO
extends
extends
Constraint
extends
Constraint Conditional type
Constraint


🔗
Conditional types


🚦
Conditional type
<type> extends <type> ? <ok_type> : <else_type>
Conditional type
<type> extends <type> ? <ok_type> : <else_type>
type X = true extends boolean ? "OK" : "ERR" // "OK"
Conditional type
<type> extends <type> ? <ok_type> : <else_type>
type X = true extends boolean ? "OK" : "ERR" // "OK"


type Y = number extends string ? "OK" : "ERR" // "ERR"
Conditional type
<type> extends <type> ? <ok_type> : <else_type>
type X = true extends boolean ? "OK" : "ERR" // "OK"


type Y = number extends string ? "OK" : "ERR" // "ERR"


type TypeName<T> =


T extends boolean ? "boolean" :


T extends string ? "string" :


T extends number ? "number" :


T extends null ? "null" :


T extends Array<any> ? "array" :


T extends object ? "object" :


T extends undefined ? "undefined" :


string;
Conditional type
<type> extends <type> ? <ok_type> : <else_type>
type X = true extends boolean ? "OK" : "ERR" // "OK"


type Y = number extends string ? "OK" : "ERR" // "ERR"


type TypeName<T> =


T extends boolean ? "boolean" :


T extends string ? "string" :


T extends number ? "number" :


T extends null ? "null" :


T extends Array<any> ? "array" :


T extends object ? "object" :


T extends undefined ? "undefined" :


string;


function typeName<T>(value: T): TypeName<T> {


// ...


}
Conditional type
<type> extends <type> ? <ok_type> : <else_type>
type X = true extends boolean ? "OK" : "ERR" // "OK"


type Y = number extends string ? "OK" : "ERR" // "ERR"


type TypeName<T> =


T extends boolean ? "boolean" :


T extends string ? "string" :


T extends number ? "number" :


T extends null ? "null" :


T extends Array<any> ? "array" :


T extends object ? "object" :


T extends undefined ? "undefined" :


string;


function typeName<T>(value: T): TypeName<T> {


// ...


}


typeName("test"); // "string"


typeName(1); // "number"


typeName(JSON.parse("{}")); // string
Typ „never”


⛔
Typ „never”
Typ „never”
function throwError(): never {


throw new Error("Some error");


}
Typ „never”
function throwError(): never {


throw new Error("Some error");


}


type FailedPromise = Promise<never>;


function asyncError(): FailedPromise {


return Promise.reject("Some error");


}
Typ „never”
function throwError(): never {


throw new Error("Some error");


}


type FailedPromise = Promise<never>;


function asyncError(): FailedPromise {


return Promise.reject("Some error");


}


type EmptyObject = Record<any, never>;
Typ „never”
function throwError(): never {


throw new Error("Some error");


}


type FailedPromise = Promise<never>;


function asyncError(): FailedPromise {


return Promise.reject("Some error");


}


type EmptyObject = Record<any, never>;


const test1: EmptyObject = { x: 1 }; // Error


const test2: EmptyObject = {}; // OK
Typ „never”
type EmptyArray = never[];
function throwError(): never {


throw new Error("Some error");


}


type FailedPromise = Promise<never>;


function asyncError(): FailedPromise {


return Promise.reject("Some error");


}


type EmptyObject = Record<any, never>;


const test1: EmptyObject = { x: 1 }; // Error


const test2: EmptyObject = {}; // OK
Lookup typów


🔍
type ComplexType = {


foo: {


a: string;


b: string;


c: string;


bar: {


x: number;


y: number;


}


},


}


type Foo = ComplexType["foo"]; // { a, b, c, ... }


type Bar = ComplexType["foo"]["bar"]; // { x, y }
export type Users = { id: string, … }[];


type User =
export type Users = { id: string, … }[];


type User = Users[number];
Case study: CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
export class CommandBus
{

private availableHandlers: CommandHandlers
;

constructor(commandHandlers: CommandHandler[])
{

this.availableHandlers = commandHandlers.reduce((handlers: CommandHandlers, handler) =>
{

handlers[handler.commandType] = handler
;

return handlers
;

}, {})
;

}

public execute(command: any)
{

if (!this.availableHandlers[command.type])
{

return Promise.reject(new Error(`Command: ${command.type} is not supported.`))
;

}

return this.availableHandlers[command.type].execute(command)
;

}

}

CommandHandlerA
CommandHandlerB
CommandA
CommandB
CommandBus
import LoginHandler from "../app/features/users/handlers/login.handler"
;

import DeleteUserHandler from "../app/features/users/handlers/delete-user.handler"
;

// HANDLERS_IMPORT
S

export async function registerCommandHandlers(container: AwilixContainer)
{

container.register(
{

commandHandlers: asArray<any>(
[

awilix.asClass(LoginHandler)
,

awilix.asClass(DeleteUserHandler)
,

// COMMAND_HANDLERS_SETU
P

])
,

})
;

return container
;

}
DEMO
type DeleteUserCommand =
{

type: string
;

payload:
{

id?: string | null | undefined
;

}

}

Dlaczego?
type DeleteUserCommand =
{

type: string
;

payload:
{

id?: string | null | undefined
;

}

}

type FooCommand =
{

type: string
;

payload: {}
;

}
Dlaczego?
type DeleteUserCommand =
{

type: string
;

payload:
{

id?: string | null | undefined
;

}

}

type FooCommand =
{

type: string
;

payload: {}
;

}
Dlaczego?
type DeleteUserCommand =
{

type: string
;

payload:
{

id?: string | null | undefined
;

}

}

type FooCommand =
{

type: string
;

payload: {}
;

}
Rozwiązanie?
type DeleteUserCommand =
{

type: string
;

payload:
{

id?: string | null | undefined
;

}

}

type FooCommand =
{

type: string
;

payload: {}
;

}
Rozwiązanie?
type DeleteUserCommand =
{

type: "users/DELETE_USER"
;

payload:
{

id?: string | null | undefined
;

}

}

type FooCommand =
{

type: "foo"
;

payload: {}
;

}
Kiedy runtime error jest
nieunikniony…
Problem: dane wejściowe
Problem: dane wejściowe
Pole formularza
Problem: dane wejściowe
Pole formularza
Odpowiedź z serwera
Problem: dane wejściowe
Request
Pole formularza
Odpowiedź z serwera
Problem: dane wejściowe
Request
Pole formularza
Plik
Odpowiedź z serwera
Problem: dane wejściowe
Request
Pole formularza
Plik
Zmienne środowiskowe
Odpowiedź z serwera
Problem: dane wejściowe
Request
Pole formularza
Plik
Zmienne środowiskowe
Odpowiedź z serwera
Baza danych
Zmienne środowiskowe
Zmienne środowiskowe
MAX_FAILED_LOG_IN_ATTEMPTS=
Zmienne środowiskowe
MAX_FAILED_LOG_IN_ATTEMPTS= 3
Zmienne środowiskowe
MAX_FAILED_LOG_IN_ATTEMPTS= 3
MAX_FAILED_LOG_IN_ATTEMPTS=
Zmienne środowiskowe
MAX_FAILED_LOG_IN_ATTEMPTS= 3
MAX_FAILED_LOG_IN_ATTEMPTS= DUNNO
Zmienne środowiskowe
MAX_FAILED_LOG_IN_ATTEMPTS= 3
MAX_FAILED_LOG_IN_ATTEMPTS= DUNNO
MAX_FAILED_LOG_IN_ATTEMPTS=
Zmienne środowiskowe
MAX_FAILED_LOG_IN_ATTEMPTS= 3
MAX_FAILED_LOG_IN_ATTEMPTS= DUNNO
MAX_FAILED_LOG_IN_ATTEMPTS= =3
Zmienne środowiskowe
Zmienne środowiskowe
EXTERNAL_API_URL=
Zmienne środowiskowe
EXTERNAL_API_URL= https://api.com/v1/
Zmienne środowiskowe
EXTERNAL_API_URL= https://api.com/v1/
EXTERNAL_API_URL=
Zmienne środowiskowe
EXTERNAL_API_URL= https://api.com/v1/
EXTERNAL_API_URL= foo
Case: niesprawdzona konfiguracja
Case: niesprawdzona konfiguracja
URL: „foo”
Case: niesprawdzona konfiguracja
Endpoint A: nie korzysta z URLa
URL: „foo”
Case: niesprawdzona konfiguracja
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
URL: „foo”
Case: niesprawdzona konfiguracja
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
🕓 czas
URL: „foo”
Case: niesprawdzona konfiguracja
Start aplikacji
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
🕓 czas
URL: „foo”
Case: niesprawdzona konfiguracja
Start aplikacji Request do A
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
🕓 czas
URL: „foo”
Case: niesprawdzona konfiguracja
Start aplikacji Request do A
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
Request do A
🕓 czas
URL: „foo”
Case: niesprawdzona konfiguracja
Start aplikacji Request do A
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
Request do A Request do B
🕓 czas
💥
URL: „foo”
TypeScript as a runtime error terminator
Case: zwalidowana/sparsowana konfiguracja
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
URL: „foo”
Case: zwalidowana/sparsowana konfiguracja
🕓 czas
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
URL: „foo”
Case: zwalidowana/sparsowana konfiguracja
Start aplikacji
🕓 czas
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
URL: „foo”
Case: zwalidowana/sparsowana konfiguracja
Start aplikacji
Parsowanie kon
fi
guracji
🕓 czas
💥
Endpoint A: nie korzysta z URLa
Endpoint B: korzysta z URLa
URL: „foo”
Kontrola graniczna


🛂
Kontrola graniczna
Function
🛂
Input TS App
🛂
Input
import { URL } from "url"
;

export const appConfig =
{

externalApiUrl: new URL(process.env.EXTERNAL_API_URL || "")
,

maxFailedLoginAttempts: parseInteger(process.env.MAX_FAILED_LOG_IN_ATTEMPTS || "")
,

}
;

export type AppConfig = typeof appConfig
;

function parseInteger(value: string): number
{

const parsedInt = parseInt(value)
;

if (!Number.isInteger(parsedInt))
{

throw new Error(`Expected integer, got: "${value}"`)
;

}

return parsedInt
;

}
Podsumowanie
Podsumowanie
• 🧘 Single source of truth
Podsumowanie
• 🧘 Single source of truth
• Na poziomie typów (przykład z encją User)
Podsumowanie
• 🧘 Single source of truth
• Na poziomie typów (przykład z encją User)
• typeof na const
Podsumowanie
• 🧘 Single source of truth
• Na poziomie typów (przykład z encją User)
• typeof na const
• 🔀 TS umożliwia wprowadzenie logiki na poziomie typów
Podsumowanie
• 🧘 Single source of truth
• Na poziomie typów (przykład z encją User)
• typeof na const
• 🔀 TS umożliwia wprowadzenie logiki na poziomie typów
• Generyki + type inference
Podsumowanie
• 🧘 Single source of truth
• Na poziomie typów (przykład z encją User)
• typeof na const
• 🔀 TS umożliwia wprowadzenie logiki na poziomie typów
• Generyki + type inference
• Zablokowanie kompilacji przez niepasujący typ
Podsumowanie
• 🧘 Single source of truth
• Na poziomie typów (przykład z encją User)
• typeof na const
• 🔀 TS umożliwia wprowadzenie logiki na poziomie typów
• Generyki + type inference
• Zablokowanie kompilacji przez niepasujący typ
• 🛂 Parsuj dane z zewnątrz jak wcześnie to możliwe
Inne fajne zagadnienia
Inne fajne zagadnienia
• Typed errors

• https://hegel.js.org/

• https://rlee.dev/writing/practical-guide-to-fp-ts-part-3#either
Inne fajne zagadnienia
• Typed errors

• https://hegel.js.org/

• https://rlee.dev/writing/practical-guide-to-fp-ts-part-3#either
• Nominal/brand/opaque types

• https://basarat.gitbook.io/typescript/main-1/nominaltyping

• https://michalzalecki.com/nominal-typing-in-typescript/
Inne fajne zagadnienia
• Typed errors

• https://hegel.js.org/

• https://rlee.dev/writing/practical-guide-to-fp-ts-part-3#either
• Nominal/brand/opaque types

• https://basarat.gitbook.io/typescript/main-1/nominaltyping

• https://michalzalecki.com/nominal-typing-in-typescript/
• Mapped types

• https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
Inne fajne zagadnienia
• Typed errors

• https://hegel.js.org/

• https://rlee.dev/writing/practical-guide-to-fp-ts-part-3#either
• Nominal/brand/opaque types

• https://basarat.gitbook.io/typescript/main-1/nominaltyping

• https://michalzalecki.com/nominal-typing-in-typescript/
• Mapped types

• https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
• Phantom builder pattern

• https://medium.com/carwow-product-engineering/phantom-builder-pattern-in-elm-2fcb950a4e36

• https://stackover
fl
ow.com/questions/65029441/how-to-implement-a-type-safe-phantom-types-based-builder-in-typescript

• https://blog.scottlogic.com/2020/09/16/typescript-builders.html
TypeScript as a runtime error terminator
TypeScript as a runtime error terminator
Dzięki!

More Related Content

PDF
Architektura ngrx w angular 2+
PDF
Budowa elementów GUI za pomocą biblioteki React - szybki start
PDF
Znaki mocy dla laików – Programowanie funkcyjne w JavaScript
PDF
Podstawy AngularJS
PDF
Wprowadzenie do technologii Big Data
PPTX
Konrad Kokosa - Pamięć w .NET - od ogólu do szczegółu- 4developers2016
PPT
Podstawy php
Architektura ngrx w angular 2+
Budowa elementów GUI za pomocą biblioteki React - szybki start
Znaki mocy dla laików – Programowanie funkcyjne w JavaScript
Podstawy AngularJS
Wprowadzenie do technologii Big Data
Konrad Kokosa - Pamięć w .NET - od ogólu do szczegółu- 4developers2016
Podstawy php

What's hot (13)

PPT
Podstawy php
PDF
Nie wszystko, co ubite, w ziemi zostaje. Wprowadzenie do Event Sourcing
PDF
Technologia Xamarin i wprowadzenie do Windows IoT core
PPTX
Prezentacja php3
PDF
TGT#11 - Zostały Ci jeszcze jakieś włosy? (Testowanie programów równoległych)...
PDF
Wprowadzenie do języka Swift, czyli nowe podejście do programowania aplikacji...
PPSX
Professional Javascript for Developers
PPTX
AngularJS Warsaw #4 - Dariusz Kalbarczyk "Controller as"
PDF
React Ninja - Warsztaty TDD + React + Redux + Websockets
PDF
Python szybki start
PDF
PDF
4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski
PDF
Objective C
Podstawy php
Nie wszystko, co ubite, w ziemi zostaje. Wprowadzenie do Event Sourcing
Technologia Xamarin i wprowadzenie do Windows IoT core
Prezentacja php3
TGT#11 - Zostały Ci jeszcze jakieś włosy? (Testowanie programów równoległych)...
Wprowadzenie do języka Swift, czyli nowe podejście do programowania aplikacji...
Professional Javascript for Developers
AngularJS Warsaw #4 - Dariusz Kalbarczyk "Controller as"
React Ninja - Warsztaty TDD + React + Redux + Websockets
Python szybki start
4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski
Objective C
Ad

More from The Software House (20)

PDF
Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...
PDF
Uszanowanko Podsumowanko
PDF
Jak efektywnie podejść do certyfikacji w AWS?
PDF
O co chodzi z tą dostępnością cyfrową?
PDF
Chat tekstowy z użyciem Amazon Chime
PDF
Migracje danych serverless
PDF
Jak nie zwariować z architekturą Serverless?
PDF
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWS
PDF
Feature flags na ratunek projektu w JavaScript
PDF
Typowanie nominalne w TypeScript
PDF
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQL
PDF
Serverless Compose vs hurtownia danych
PDF
Testy API: połączenie z bazą danych czy implementacja w pamięci
PDF
Jak skutecznie read model. Case study
PDF
Firestore czyli ognista baza od giganta z Doliny Krzemowej
PDF
Jak utrzymać stado Lambd w ryzach
PDF
Jak poskromić AWS?
PDF
O łączeniu Storyblok i Next.js
PDF
Amazon Step Functions. Sposób na implementację procesów w chmurze
PDF
Od Figmy do gotowej aplikacji bez linijki kodu
Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...
Uszanowanko Podsumowanko
Jak efektywnie podejść do certyfikacji w AWS?
O co chodzi z tą dostępnością cyfrową?
Chat tekstowy z użyciem Amazon Chime
Migracje danych serverless
Jak nie zwariować z architekturą Serverless?
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWS
Feature flags na ratunek projektu w JavaScript
Typowanie nominalne w TypeScript
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQL
Serverless Compose vs hurtownia danych
Testy API: połączenie z bazą danych czy implementacja w pamięci
Jak skutecznie read model. Case study
Firestore czyli ognista baza od giganta z Doliny Krzemowej
Jak utrzymać stado Lambd w ryzach
Jak poskromić AWS?
O łączeniu Storyblok i Next.js
Amazon Step Functions. Sposób na implementację procesów w chmurze
Od Figmy do gotowej aplikacji bez linijki kodu
Ad

TypeScript as a runtime error terminator