SlideShare uma empresa Scribd logo
1 de 224
Baixar para ler offline
Nominalne typowanie
w TypeScript
Wiktor Toporek
O mnie
💼 Senior Frontend Developer
w The Software House
O mnie
💼 Senior Frontend Developer
w The Software House
Fullstack
O mnie
💼 Senior Frontend Developer
w The Software House
Fullstack
Elm
O mnie
💼 Senior Frontend Developer
w The Software House
Fullstack
Elm
λ Functional Programming
O mnie
💼 Senior Frontend Developer
w The Software House
Fullstack
Elm
λ Functional Programming
🪨 Static typing
O mnie
const testInvoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
function getInvoiceTotal(invoice) {
return invoice.positions.reduce(
(lastTotal, currentPosition) => lastTotal + currentPosition.price,
0
);
}
const testInvoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
function getInvoiceTotal(invoice) {
return invoice.positions.reduce(
(lastTotal, currentPosition) => lastTotal + currentPosition.price,
0
);
}
getInvoiceTotal(testInvoice) ===
const testInvoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
function getInvoiceTotal(invoice) {
return invoice.positions.reduce(
(lastTotal, currentPosition) => lastTotal + currentPosition.price,
0
);
}
getInvoiceTotal(testInvoice) === '100169.99undefined'
const testInvoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
function getInvoiceTotal(invoice) {
return invoice.positions.reduce(
(lastTotal, currentPosition) => lastTotal + currentPosition.price,
0
);
}
getInvoiceTotal(testInvoice) === '100169.99undefined'
const testInvoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
function getInvoiceTotal(invoice) {
return invoice.positions.reduce(
(lastTotal, currentPosition) => lastTotal + currentPosition.price,
0
);
}
getInvoiceTotal(testInvoice) === '100169.99undefined'
const testInvoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
function getInvoiceTotal(invoice) {
return invoice.positions.reduce(
(lastTotal, currentPosition) => lastTotal + currentPosition.price,
0
);
}
getInvoiceTotal(testInvoice) === '100169.99undefined'
type Invoice = {
positions: InvoicePosition[];
}
type Invoice = {
positions: InvoicePosition[];
}
type InvoicePosition = {
productName: string;
price: number;
}
type Invoice = {
positions: InvoicePosition[];
}
type InvoicePosition = {
productName: string;
price: number;
}
const testInvoice: Invoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
type Invoice = {
positions: InvoicePosition[];
}
type InvoicePosition = {
productName: string;
price: number;
}
const testInvoice: Invoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
type Invoice = {
positions: InvoicePosition[];
}
type InvoicePosition = {
productName: string;
price: number;
}
const testInvoice: Invoice = {
positions: [
{ productName: "JavaScript: The Good Parts", price: 100 },
{ productName: "CSS in Depth", price: "169.99" },
{ productName: "Functional Programming in JavaScript", prince: 150.50 },
],
}
OO w JS
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
Object.prototype
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(s
s
s
s
s
s
s
s
);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(s
s
s
s
s
s
s
s
);
✅
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(s
s
s
s
s
s
s
s
);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook("12345");
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(3.14);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(undefined);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(z
z
z
z
z
);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(z
z
z
z
z
);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(z
z
z
z
z
);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(user1);
const user1 = new User("123-123-123", "John Doe", "john@doe.com");
const someBook = new Book("12345", "JavaScript: The Good Parts");
user1.addFavoriteBook(user1);
😬
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book User
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book User
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book User
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book User
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book User
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book ⊄ User
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book User
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
Book
User
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
User Book
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
User Book
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
User Book
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
User Book
class Book {
constructor(
public id: string,
public name: string,
public isbn?: string
) {}
}
class User {
favoriteBooks: Book[] = [];
constructor(
public id: string,
public name: string,
public email: string
) {}
addFavoriteBook(book: Book) {
this.favoriteBooks.push(book);
}
}
type Book = {
id: string;
name: string;
isbn?: string;
}
type User = {
id: string;
name: string;
email: string;
favoriteBooks: Book[];
addFavoriteBook: (book: Book) => void;
}
User ⊂ Book
“if it looks like a duck, swims like a
duck, and quacks like a duck, then it
probably is a duck”
Duck typing
“if it looks like a duck, swims like a
duck, and quacks like a duck, then it
probably is a duck”
Duck typing
~JavaScript
Case study 1:
🪪 ID encji
function addBookToUserFavorites(userId: string, bookId: string) {
// ...
}
addBookToUserFavorites(
,
,
);
'716fccd0-73fd-4fbf-be44-7c3176242962'
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'
function addBookToUserFavorites(userId: string, bookId: string) {
// ...
}
addBookToUserFavorites(
,
,
);
'716fccd0-73fd-4fbf-be44-7c3176242962'
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'
Nazwane parametry
function addBookToUserFavorites(userId: string, bookId: string) {
// ...
}
function addBookToUserFavorites(userId: string, bookId: string) {
// ...
}
function addBookToUserFavorites({ userId, bookId }: { userId: string, bookId: string }) {
// ...
}
function addBookToUserFavorites(userId: string, bookId: string) {
// ...
}
function addBookToUserFavorites({ userId, bookId }: { userId: string, bookId: string }) {
// ...
}
addBookToUserFavorites({
bookId: 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
userId: '716fccd0-73fd-4fbf-be44-7c3176242962',
);
Value Object
class UserId {
constructor(public id: string) {}
}
class BookId {
constructor(public id: string) {}
}
class UserId {
constructor(public id: string) {}
}
class BookId {
constructor(public id: string) {}
}
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
class UserId {
constructor(public id: string) {}
}
class BookId {
constructor(public id: string) {}
}
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962');
const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2');
addBookToUserFavorites(bookId, userId);
class UserId {
constructor(public id: string) {}
}
class BookId {
constructor(public id: string) {}
}
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962');
const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2');
addBookToUserFavorites(bookId, userId);
class UserId {
constructor(public id: string) {}
}
class BookId {
constructor(public id: string) {}
}
private type = 'user';
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962');
const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2');
addBookToUserFavorites(bookId, userId);
class UserId {
constructor(public id: string) {}
}
class BookId {
constructor(public id: string) {}
}
private type = 'user';
private type = 'book';
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962');
const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2');
addBookToUserFavorites(bookId, userId);
class UserId {
constructor(public id: string) {}
}
class BookId {
constructor(public id: string) {}
}
private type = 'user';
private type = 'book';
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962');
const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2');
addBookToUserFavorites(bookId, userId);
Case study 2:
🕑 Czas
async function delayedHelloWorld() {
await delay(1000);
console.log('Hello World');
}
async function delayedHelloWorld() {
await delay(1000);
console.log('Hello World');
}
const delay = (timeInterval: number) => new Promise(
resolve => setTimeout(resolve, timeInterval)
);
async function delayedHelloWorld() {
await delay(1000);
console.log('Hello World');
}
const delay = (timeInterval: number) => new Promise(
resolve => setTimeout(resolve, timeInterval)
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
https://www.simscale.com/blog/nasa-mars-climate-orbiter-metric/
async function delayedHelloWorld() {
await delay(1000);
console.log('Hello World');
}
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: number) => new Promise(
resolve => setTimeout(resolve, timeInterval)
);
async function delayedHelloWorld() {
await delay(1000);
console.log('Hello World');
}
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: number) => new Promise(
resolve => setTimeout(resolve, timeInterval)
);
const delay = (timeIntervalInMilliseconds: number) => new Promise(
resolve => setTimeout(resolve, timeInterval)
);
Value Object!
class TimeInterval {
}
class TimeInterval {
}
private value: number;
class TimeInterval {
}
private value: number;
private constructor(milliseconds: number) {
this.value = milliseconds;
}
class TimeInterval {
}
private value: number;
private constructor(milliseconds: number) {
this.value = milliseconds;
}
static fromMilliseconds(milliseconds: number) {
return new TimeInterval(milliseconds);
}
class TimeInterval {
}
private value: number;
private constructor(milliseconds: number) {
this.value = milliseconds;
}
static fromMilliseconds(milliseconds: number) {
return new TimeInterval(milliseconds);
}
static fromSeconds(seconds: number) {
return new TimeInterval(seconds * 1000);
}
class TimeInterval {
}
private value: number;
private constructor(milliseconds: number) {
this.value = milliseconds;
}
static fromMilliseconds(milliseconds: number) {
return new TimeInterval(milliseconds);
}
static fromSeconds(seconds: number) {
return new TimeInterval(seconds * 1000);
}
toMilliseconds() {
return this.value;
}
class TimeInterval {
}
private value: number;
private constructor(milliseconds: number) {
this.value = milliseconds;
}
static fromMilliseconds(milliseconds: number) {
return new TimeInterval(milliseconds);
}
static fromSeconds(seconds: number) {
return new TimeInterval(seconds * 1000);
}
toMilliseconds() {
return this.value;
}
toSeconds() {
return this.value / 1000;
}
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, timeInterval.toMilliseconds())
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, timeInterval.toMilliseconds())
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, timeInterval.toMilliseconds())
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, timeInterval.toMilliseconds())
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
async function delayedHelloWorld() {
await delay(TimeInterval.fromSeconds(1));
console.log('Hello World');
}
Case study 3:
💵 Pieniądze
{ price: 100 }
{ price: 100 }
{ price: 100 }
{ price: 100 }
Value Object!
class Money {
constructor(
public amount: number,
public currency: string,
) {}
}
class Money {
constructor(
public amount: number,
public currency: string,
) {}
}
add(money: Money): Money {
return new Money(this.amount + money.amount, this.currency);
}
class Money {
constructor(
public amount: number,
public currency: string,
) {}
}
add(money: Money): Money {
if (this.currency !== money.currency) {
throw new Error("Cannot add different currencies");
}
return new Money(this.amount + money.amount, this.currency);
}
class Money<T extends string> {
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
class Money<T extends string> {
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs = new Money(100, 'PLN');
const someEuros = new Money(100, 'EUR');
somePLNs.add(someEuros);
class Money<T extends string> {
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs = new Money(100, 'PLN');
const someEuros = new Money(100, 'EUR');
somePLNs.add(someEuros);
class Money
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs: Money<string> = new Money(100, 'PLN');
const someEuros = new Money(100, 'EUR');
somePLNs.add(someEuros);
<T e
e
e
e
e
e
e
e
e
e
e
e
e
>
>
class Money
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs: Money<string> = new Money(100, 'PLN');
const someEuros = new Money(100, 'EUR');
somePLNs.add(someEuros);
class Money
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs: Money<string> = new Money(100, 'PLN');
const someEuros = new Money(100, 'EUR');
somePLNs.add(someEuros);
<in out T extends string> {
class Money
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs: Money<string> = new Money(100, 'PLN');
const someEuros = new Money(100, 'EUR');
somePLNs.add(someEuros);
<in out T extends string> {
class Money
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs: Money<string> = new Money(100, 'PLN');
const someEuros = new Money(100, 'EUR');
somePLNs.add(someEuros);
<in out T extends string> {
class Money
constructor(
public amount: number,
public currency: T,
) {}
add(money: Money<T>): Money<T> {
return new Money(this.amount + money.amount, this.currency);
}
}
const somePLNs = new Money(100, 'PLN' as string);
const someEuros = new Money(100, 'EUR' as string);
somePLNs.add(someEuros);
<T extends string> {
<in out T extends string> {
A co z Functional
Programming?
Nominal Typing?
🤔
Opaque types
Opaque types
Branded types
Opaque types
Branded types
Nominal types
https://flow.org/en/
https://flow.org/en/docs/types/opaque-types/
Case study 1:
🪪 ID encji
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
TypeScript nie istnieje w runtime
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
type UserId = string & { _type: 'user_id' };
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
type UserId = string & { _type: 'user_id' };
type BookId = string & { _type: 'book_id' };
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
type UserId = string & { _type: 'user_id' };
type BookId = string & { _type: 'book_id' };
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
type UserId = string & { _type: 'user_id' };
type BookId = string & { _type: 'book_id' };
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
type UserId = string & { _type: 'user_id' };
type BookId = string & { _type: 'book_id' };
type UserId = string;
function addBookToUserFavorites(userId: UserId, bookId: BookId) {
// ...
}
type BookId = string;
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962',
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2',
);
type UserId = string & { _type: 'user_id' };
type BookId = string & { _type: 'book_id' };
addBookToUserFavorites(
'716fccd0-73fd-4fbf-be44-7c3176242962' as UserId,
'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2' as BookId,
);
type UserId = string & { _type: 'user_id' };
type UserId = string & { _type: 'user_id' };
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string object['_type']
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string object['_type']
| number
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string object['_type']
| number array[0]
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string object['_type']
| number array[0]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string object['_type']
| number array[0]
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string object['_type']
| number array[0]
| symbol
type UserId = string & { _type: 'user_id' };
type Property = keyof any;
| string object['_type']
| number array[0]
| symbol object[Symbol('a')] = 'a';
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html
type UserId = string & { _type: 'user_id' };
type UserId = string & { _type: 'user_id' };
declare const Nominal: unique symbol;
type UserId = string & { _type: 'user_id' };
declare const Nominal: unique symbol;
type UserId = string & { [Nominal]: 'user_id' };
type UserId = string & { _type: 'user_id' };
declare const Nominal: unique symbol;
type UserId = string & { [Nominal]: 'user_id' };
type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal };
type UserId = string & { _type: 'user_id' };
declare const Nominal: unique symbol;
type UserId = string & { [Nominal]: 'user_id' };
type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal };
type UserId = NominalType<string, 'user_id'>
type UserId = string & { _type: 'user_id' };
declare const Nominal: unique symbol;
type UserId = string & { [Nominal]: 'user_id' };
type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal };
type UserId = NominalType<string, 'user_id'>
type BookId = NominalType<string, 'book_id'>
Backend
Backend Frontend
Backend Frontend
Kontrakt
Backend Frontend
Kontrakt
GET /books
{ id: BookId }[]
Backend Frontend
Kontrakt
GET /books
{ id: BookId }[]
POST /favorites
{ id: BookId }
Case study 2:
🕑 Czas
async function delayedHelloWorld() {
await delay(1000);
console.log('Hello World');
}
const delay = (timeInterval: number) => new Promise(
resolve => setTimeout(resolve, timeInterval)
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
type TimeInterval = NominalType<number, 'TimeInterval'>;
type TimeInterval = NominalType<number, 'TimeInterval'>;
const milliseconds = (howMany: number) => howMany as TimeInterval;
const seconds = (howMany: number) => (howMany * 1000) as TimeInterval;
type TimeInterval = NominalType<number, 'TimeInterval'>;
const milliseconds = (howMany: number) => howMany as TimeInterval;
const seconds = (howMany: number) => (howMany * 1000) as TimeInterval;
const toMilliseconds = (timeInterval: TimeInterval) => timeInterval as number;
const toSeconds = (timeInterval: TimeInterval) => timeInterval / 1000;
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, toMilliseconds(timeInterval))
);
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, toMilliseconds(timeInterval))
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, toMilliseconds(timeInterval))
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, toMilliseconds(timeInterval))
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
const delay = (timeInterval: TimeInterval) => new Promise(
resolve => setTimeout(resolve, toMilliseconds(timeInterval))
);
async function delayedHelloWorld() {
await delay(1);
console.log('Hello World');
}
async function delayedHelloWorld() {
await delay(seconds(1));
console.log('Hello World');
}
Case study 3:
💵 Pieniądze
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Money<'EUR'>;
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Money<'EUR'>;
const somePLNs = moneyInPLN(100);
const someEuros = moneyInEUR(100);
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Money<'EUR'>;
const somePLNs = moneyInPLN(100);
const someEuros = moneyInEUR(100);
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'EUR'> = somePLNs;
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Money<'EUR'>;
const somePLNs = moneyInPLN(100);
const someEuros = moneyInEUR(100);
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'EUR'> = somePLNs;
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Money<'EUR'>;
const somePLNs = moneyInPLN(100);
const someEuros = moneyInEUR(100);
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'EUR'> = somePLNs;
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'PLN'> = somePLNs;
const sum = amount1 + amount2;
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'PLN'> = somePLNs;
const sum = amount1 + amount2;
const sum = 1 + 1;
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'PLN'> = somePLNs;
const sum = amount1 + amount2;
const sum = 1 + 1;
const sum = {} + {};
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'PLN'> = somePLNs;
const sum = amount1 + amount2;
const sum = 1 + 1;
const sum = {} + {};
const amount1: Money<'EUR'> = someEuros;
const amount2: Money<'PLN'> = somePLNs;
const sum = amount1 + amount2;
const sum = 1 + 1;
const sum = {} + {};
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>;
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>;
const sum = someEuros + somePLNs;
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>;
const sum = someEuros + somePLNs;
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
declare const Nominal: unique symbol;
type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency };
const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>;
const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>;
const sum = someEuros + somePLNs;
function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney {
return amount1 as any + amount2;
}
function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney {
return amount1 as any + amount2;
}
const sum = addMoney(somePLNs, someEuros)
function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney {
return amount1 as any + amount2;
}
const sum = addMoney(somePLNs, someEuros)
function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney {
return amount1 as any + amount2;
}
const sum = addMoney(somePLNs, someEuros)
Podsumowanie
Typowanie strukturalne + OO bywa pułapką
Typowanie strukturalne + OO bywa pułapką
user1.addFavoriteBook(user1);
Możliwa jest symulacja typów nominalnych w TS
Możliwa jest symulacja typów nominalnych w TS
declare const Nominal: unique symbol;
Możliwa jest symulacja typów nominalnych w TS
declare const Nominal: unique symbol;
type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal };
Możemy dodać prymitywnym typom nominały
Możemy dodać prymitywnym typom nominały
type UserId = NominalType<string, 'user_id'>
type BookId = NominalType<string, 'book_id'>
Case study z pieniędzmi to być może nie najlepsze zastosowanie,
Case study z pieniędzmi to być może nie najlepsze zastosowanie,
ale warto wiedzieć że w TS istnieje masa sztuczek ;-)
Case study z pieniędzmi to być może nie najlepsze zastosowanie,
ale warto wiedzieć że w TS istnieje masa sztuczek ;-)
Enkapsulacja operacji na prymitywnych typach
Case study z pieniędzmi to być może nie najlepsze zastosowanie,
ale warto wiedzieć że w TS istnieje masa sztuczek ;-)
Enkapsulacja operacji na prymitywnych typach
Opaque types
Typy nominalne mogą czuwać nad liczbami i jednostkami
Typy nominalne mogą czuwać nad liczbami i jednostkami
async function delayedHelloWorld() {
await delay(seconds(1));
console.log('Hello World');
}
Typy nominalne mogą czuwać nad liczbami i jednostkami
async function delayedHelloWorld() {
await delay(seconds(1));
console.log('Hello World');
}
Prymitywne typy pod spodem
Typy nominalne mogą czuwać nad liczbami i jednostkami
async function delayedHelloWorld() {
await delay(seconds(1));
console.log('Hello World');
}
Prymitywne typy pod spodem
Terser?
Typy nominalne mogą czuwać nad liczbami i jednostkami
async function delayedHelloWorld() {
await delay(seconds(1));
console.log('Hello World');
}
Prymitywne typy pod spodem
Terser?
Inlining przy kompilacji
Typy nominalne mogą czuwać nad liczbami i jednostkami
async function delayedHelloWorld() {
await delay(seconds(1));
console.log('Hello World');
}
Prymitywne typy pod spodem
Terser?
Inlining przy kompilacji
async function delayedHelloWorld() {
await delay(1000);
console.log('Hello World');
}
Dziękuje za uwagę!
Wiktor Toporek
Senior Frontend Developer
✉ wiktor.toporek@tsh.io
Twitter: @vViktorPL
tsh.io
✉ wtoporek@gmail.com
tsh.io/programowanko
Dziękuje za uwagę!
Wiktor Toporek
Senior Frontend Developer
✉ wiktor.toporek@tsh.io
Twitter: @vViktorPL
tsh.io
Q & A
✉ wtoporek@gmail.com
tsh.io/programowanko

Mais conteúdo relacionado

Semelhante a Typowanie nominalne w TypeScript

Type script by Howard
Type script by HowardType script by Howard
Type script by HowardLearningTech
 
Protocols
ProtocolsProtocols
ProtocolsSV.CO
 
JavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashJavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashBret Little
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsIván López Martín
 
TypeScriptで書くAngularJS @ GDG神戸2014.8.23
TypeScriptで書くAngularJS @ GDG神戸2014.8.23TypeScriptで書くAngularJS @ GDG神戸2014.8.23
TypeScriptで書くAngularJS @ GDG神戸2014.8.23Okuno Kentaro
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyIván López Martín
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimizedWoody Pewitt
 
Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4DEVCON
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?PROIDEA
 
JavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptxJavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptxMegha V
 
Tools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 EditionTools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 EditionJesus Manuel Olivas
 
Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Julien Truffaut
 
How to ship customer value faster with step functions
How to ship customer value faster with step functionsHow to ship customer value faster with step functions
How to ship customer value faster with step functionsYan Cui
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesNebojša Vukšić
 
How to ship customer value faster with step functions
How to ship customer value faster with step functionsHow to ship customer value faster with step functions
How to ship customer value faster with step functionsYan Cui
 

Semelhante a Typowanie nominalne w TypeScript (20)

Type script by Howard
Type script by HowardType script by Howard
Type script by Howard
 
Protocols
ProtocolsProtocols
Protocols
 
JavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashJavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and Lodash
 
CSharp v1.0.2
CSharp v1.0.2CSharp v1.0.2
CSharp v1.0.2
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy Annotations
 
TypeScriptで書くAngularJS @ GDG神戸2014.8.23
TypeScriptで書くAngularJS @ GDG神戸2014.8.23TypeScriptで書くAngularJS @ GDG神戸2014.8.23
TypeScriptで書くAngularJS @ GDG神戸2014.8.23
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovy
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
 
Javascripting.pptx
Javascripting.pptxJavascripting.pptx
Javascripting.pptx
 
Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?
 
JavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptxJavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptx
 
Functional Programming with C#
Functional Programming with C#Functional Programming with C#
Functional Programming with C#
 
Tools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 EditionTools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 Edition
 
Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!
 
How to ship customer value faster with step functions
How to ship customer value faster with step functionsHow to ship customer value faster with step functions
How to ship customer value faster with step functions
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examples
 
C# Is The Future
C# Is The FutureC# Is The Future
C# Is The Future
 
How to ship customer value faster with step functions
How to ship customer value faster with step functionsHow to ship customer value faster with step functions
How to ship customer value faster with step functions
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 

Mais de The Software House

Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...
Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...
Jak kraść miliony, czyli o błędach bezpieczeństwa, które mogą spotkać również...The Software House
 
Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?The Software House
 
O co chodzi z tą dostępnością cyfrową?
O co chodzi z tą dostępnością cyfrową?O co chodzi z tą dostępnością cyfrową?
O co chodzi z tą dostępnością cyfrową?The Software House
 
Chat tekstowy z użyciem Amazon Chime
Chat tekstowy z użyciem Amazon ChimeChat tekstowy z użyciem Amazon Chime
Chat tekstowy z użyciem Amazon ChimeThe Software House
 
Jak nie zwariować z architekturą Serverless?
Jak nie zwariować z architekturą Serverless?Jak nie zwariować z architekturą Serverless?
Jak nie zwariować z architekturą Serverless?The Software House
 
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWS
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWSAnaliza semantyczna artykułów prasowych w 5 sprintów z użyciem AWS
Analiza semantyczna artykułów prasowych w 5 sprintów z użyciem AWSThe Software House
 
Feature flags na ratunek projektu w JavaScript
Feature flags na ratunek projektu w JavaScriptFeature flags na ratunek projektu w JavaScript
Feature flags na ratunek projektu w JavaScriptThe Software House
 
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQL
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQLAutomatyzacja tworzenia frontendu z wykorzystaniem GraphQL
Automatyzacja tworzenia frontendu z wykorzystaniem GraphQLThe Software House
 
Serverless Compose vs hurtownia danych
Serverless Compose vs hurtownia danychServerless Compose vs hurtownia danych
Serverless Compose vs hurtownia danychThe Software House
 
Testy API: połączenie z bazą danych czy implementacja w pamięci
Testy API: połączenie z bazą danych czy implementacja w pamięciTesty API: połączenie z bazą danych czy implementacja w pamięci
Testy API: połączenie z bazą danych czy implementacja w pamięciThe Software House
 
Jak skutecznie read model. Case study
Jak skutecznie read model. Case studyJak skutecznie read model. Case study
Jak skutecznie read model. Case studyThe Software House
 
Firestore czyli ognista baza od giganta z Doliny Krzemowej
Firestore czyli ognista baza od giganta z Doliny KrzemowejFirestore czyli ognista baza od giganta z Doliny Krzemowej
Firestore czyli ognista baza od giganta z Doliny KrzemowejThe Software House
 
Jak utrzymać stado Lambd w ryzach
Jak utrzymać stado Lambd w ryzachJak utrzymać stado Lambd w ryzach
Jak utrzymać stado Lambd w ryzachThe Software House
 
O łączeniu Storyblok i Next.js
O łączeniu Storyblok i Next.jsO łączeniu Storyblok i Next.js
O łączeniu Storyblok i Next.jsThe Software House
 
Amazon Step Functions. Sposób na implementację procesów w chmurze
Amazon Step Functions. Sposób na implementację procesów w chmurzeAmazon Step Functions. Sposób na implementację procesów w chmurze
Amazon Step Functions. Sposób na implementację procesów w chmurzeThe Software House
 
Od Figmy do gotowej aplikacji bez linijki kodu
Od Figmy do gotowej aplikacji bez linijki koduOd Figmy do gotowej aplikacji bez linijki kodu
Od Figmy do gotowej aplikacji bez linijki koduThe Software House
 
Co QA może i czego nie powinien się bać?
Co QA może i czego nie powinien się bać?Co QA może i czego nie powinien się bać?
Co QA może i czego nie powinien się bać?The Software House
 

Mais de The Software House (20)

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

Último

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusZilliz
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Zilliz
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 

Último (20)

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 

Typowanie nominalne w TypeScript

  • 3. 💼 Senior Frontend Developer w The Software House O mnie
  • 4. 💼 Senior Frontend Developer w The Software House Fullstack O mnie
  • 5. 💼 Senior Frontend Developer w The Software House Fullstack Elm O mnie
  • 6. 💼 Senior Frontend Developer w The Software House Fullstack Elm λ Functional Programming O mnie
  • 7. 💼 Senior Frontend Developer w The Software House Fullstack Elm λ Functional Programming 🪨 Static typing O mnie
  • 8. const testInvoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], } function getInvoiceTotal(invoice) { return invoice.positions.reduce( (lastTotal, currentPosition) => lastTotal + currentPosition.price, 0 ); }
  • 9. const testInvoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], } function getInvoiceTotal(invoice) { return invoice.positions.reduce( (lastTotal, currentPosition) => lastTotal + currentPosition.price, 0 ); } getInvoiceTotal(testInvoice) ===
  • 10. const testInvoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], } function getInvoiceTotal(invoice) { return invoice.positions.reduce( (lastTotal, currentPosition) => lastTotal + currentPosition.price, 0 ); } getInvoiceTotal(testInvoice) === '100169.99undefined'
  • 11. const testInvoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], } function getInvoiceTotal(invoice) { return invoice.positions.reduce( (lastTotal, currentPosition) => lastTotal + currentPosition.price, 0 ); } getInvoiceTotal(testInvoice) === '100169.99undefined'
  • 12. const testInvoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], } function getInvoiceTotal(invoice) { return invoice.positions.reduce( (lastTotal, currentPosition) => lastTotal + currentPosition.price, 0 ); } getInvoiceTotal(testInvoice) === '100169.99undefined'
  • 13. const testInvoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], } function getInvoiceTotal(invoice) { return invoice.positions.reduce( (lastTotal, currentPosition) => lastTotal + currentPosition.price, 0 ); } getInvoiceTotal(testInvoice) === '100169.99undefined'
  • 14.
  • 15. type Invoice = { positions: InvoicePosition[]; }
  • 16. type Invoice = { positions: InvoicePosition[]; } type InvoicePosition = { productName: string; price: number; }
  • 17. type Invoice = { positions: InvoicePosition[]; } type InvoicePosition = { productName: string; price: number; } const testInvoice: Invoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], }
  • 18. type Invoice = { positions: InvoicePosition[]; } type InvoicePosition = { productName: string; price: number; } const testInvoice: Invoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], }
  • 19. type Invoice = { positions: InvoicePosition[]; } type InvoicePosition = { productName: string; price: number; } const testInvoice: Invoice = { positions: [ { productName: "JavaScript: The Good Parts", price: 100 }, { productName: "CSS in Depth", price: "169.99" }, { productName: "Functional Programming in JavaScript", prince: 150.50 }, ], }
  • 21. function Person(first, last, age, eyecolor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyecolor; } Person.prototype.name = function() { return this.firstName + " " + this.lastName; };
  • 22. Object.prototype function Person(first, last, age, eyecolor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyecolor; } Person.prototype.name = function() { return this.firstName + " " + this.lastName; };
  • 23.
  • 24. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} }
  • 25. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } }
  • 26. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } } const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts");
  • 27. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts");
  • 28. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts");
  • 29. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(
  • 30. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(s s s s s s s s );
  • 31. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(s s s s s s s s ); ✅
  • 32. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(s s s s s s s s );
  • 33. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(
  • 34. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook("12345");
  • 35. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(3.14);
  • 36. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(undefined);
  • 37. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(z z z z z );
  • 38. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(z z z z z );
  • 39. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(z z z z z );
  • 40. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(
  • 41. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(user1);
  • 42. const user1 = new User("123-123-123", "John Doe", "john@doe.com"); const someBook = new Book("12345", "JavaScript: The Good Parts"); user1.addFavoriteBook(user1); 😬
  • 43.
  • 44. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } }
  • 45. class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } } type Book = { id: string; name: string; isbn?: string; }
  • 46. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; }
  • 47. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book
  • 48. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book User
  • 49. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book User
  • 50. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book User
  • 51. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book User
  • 52. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book User
  • 53. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book ⊄ User
  • 54. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book User
  • 55. type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } Book User
  • 56. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } } type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } User Book
  • 57. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } } type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } User Book
  • 58. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } } type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } User Book
  • 59. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } } type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } User Book
  • 60. class Book { constructor( public id: string, public name: string, public isbn?: string ) {} } class User { favoriteBooks: Book[] = []; constructor( public id: string, public name: string, public email: string ) {} addFavoriteBook(book: Book) { this.favoriteBooks.push(book); } } type Book = { id: string; name: string; isbn?: string; } type User = { id: string; name: string; email: string; favoriteBooks: Book[]; addFavoriteBook: (book: Book) => void; } User ⊂ Book
  • 61. “if it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck” Duck typing
  • 62. “if it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck” Duck typing ~JavaScript
  • 63.
  • 64. Case study 1: 🪪 ID encji
  • 65. function addBookToUserFavorites(userId: string, bookId: string) { // ... } addBookToUserFavorites( , , ); '716fccd0-73fd-4fbf-be44-7c3176242962' 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'
  • 66. function addBookToUserFavorites(userId: string, bookId: string) { // ... } addBookToUserFavorites( , , ); '716fccd0-73fd-4fbf-be44-7c3176242962' 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'
  • 69. function addBookToUserFavorites(userId: string, bookId: string) { // ... } function addBookToUserFavorites({ userId, bookId }: { userId: string, bookId: string }) { // ... }
  • 70. function addBookToUserFavorites(userId: string, bookId: string) { // ... } function addBookToUserFavorites({ userId, bookId }: { userId: string, bookId: string }) { // ... } addBookToUserFavorites({ bookId: 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', userId: '716fccd0-73fd-4fbf-be44-7c3176242962', );
  • 72. class UserId { constructor(public id: string) {} } class BookId { constructor(public id: string) {} }
  • 73. class UserId { constructor(public id: string) {} } class BookId { constructor(public id: string) {} } function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... }
  • 74. class UserId { constructor(public id: string) {} } class BookId { constructor(public id: string) {} } function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962'); const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'); addBookToUserFavorites(bookId, userId);
  • 75. class UserId { constructor(public id: string) {} } class BookId { constructor(public id: string) {} } function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962'); const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'); addBookToUserFavorites(bookId, userId);
  • 76. class UserId { constructor(public id: string) {} } class BookId { constructor(public id: string) {} } private type = 'user'; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962'); const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'); addBookToUserFavorites(bookId, userId);
  • 77. class UserId { constructor(public id: string) {} } class BookId { constructor(public id: string) {} } private type = 'user'; private type = 'book'; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962'); const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'); addBookToUserFavorites(bookId, userId);
  • 78. class UserId { constructor(public id: string) {} } class BookId { constructor(public id: string) {} } private type = 'user'; private type = 'book'; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } const userId = new UserId('716fccd0-73fd-4fbf-be44-7c3176242962'); const bookId = new BookId('a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2'); addBookToUserFavorites(bookId, userId);
  • 80. async function delayedHelloWorld() { await delay(1000); console.log('Hello World'); }
  • 81. async function delayedHelloWorld() { await delay(1000); console.log('Hello World'); } const delay = (timeInterval: number) => new Promise( resolve => setTimeout(resolve, timeInterval) );
  • 82. async function delayedHelloWorld() { await delay(1000); console.log('Hello World'); } const delay = (timeInterval: number) => new Promise( resolve => setTimeout(resolve, timeInterval) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 84.
  • 85.
  • 86. async function delayedHelloWorld() { await delay(1000); console.log('Hello World'); } async function delayedHelloWorld() { await delay(1); console.log('Hello World'); } const delay = (timeInterval: number) => new Promise( resolve => setTimeout(resolve, timeInterval) );
  • 87. async function delayedHelloWorld() { await delay(1000); console.log('Hello World'); } async function delayedHelloWorld() { await delay(1); console.log('Hello World'); } const delay = (timeInterval: number) => new Promise( resolve => setTimeout(resolve, timeInterval) ); const delay = (timeIntervalInMilliseconds: number) => new Promise( resolve => setTimeout(resolve, timeInterval) );
  • 91. class TimeInterval { } private value: number; private constructor(milliseconds: number) { this.value = milliseconds; }
  • 92. class TimeInterval { } private value: number; private constructor(milliseconds: number) { this.value = milliseconds; } static fromMilliseconds(milliseconds: number) { return new TimeInterval(milliseconds); }
  • 93. class TimeInterval { } private value: number; private constructor(milliseconds: number) { this.value = milliseconds; } static fromMilliseconds(milliseconds: number) { return new TimeInterval(milliseconds); } static fromSeconds(seconds: number) { return new TimeInterval(seconds * 1000); }
  • 94. class TimeInterval { } private value: number; private constructor(milliseconds: number) { this.value = milliseconds; } static fromMilliseconds(milliseconds: number) { return new TimeInterval(milliseconds); } static fromSeconds(seconds: number) { return new TimeInterval(seconds * 1000); } toMilliseconds() { return this.value; }
  • 95. class TimeInterval { } private value: number; private constructor(milliseconds: number) { this.value = milliseconds; } static fromMilliseconds(milliseconds: number) { return new TimeInterval(milliseconds); } static fromSeconds(seconds: number) { return new TimeInterval(seconds * 1000); } toMilliseconds() { return this.value; } toSeconds() { return this.value / 1000; }
  • 96. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, timeInterval.toMilliseconds()) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 97. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, timeInterval.toMilliseconds()) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 98. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, timeInterval.toMilliseconds()) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 99. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, timeInterval.toMilliseconds()) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); } async function delayedHelloWorld() { await delay(TimeInterval.fromSeconds(1)); console.log('Hello World'); }
  • 100. Case study 3: 💵 Pieniądze
  • 106. class Money { constructor( public amount: number, public currency: string, ) {} }
  • 107. class Money { constructor( public amount: number, public currency: string, ) {} } add(money: Money): Money { return new Money(this.amount + money.amount, this.currency); }
  • 108. class Money { constructor( public amount: number, public currency: string, ) {} } add(money: Money): Money { if (this.currency !== money.currency) { throw new Error("Cannot add different currencies"); } return new Money(this.amount + money.amount, this.currency); }
  • 109. class Money<T extends string> { constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } }
  • 110. class Money<T extends string> { constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs = new Money(100, 'PLN'); const someEuros = new Money(100, 'EUR'); somePLNs.add(someEuros);
  • 111. class Money<T extends string> { constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs = new Money(100, 'PLN'); const someEuros = new Money(100, 'EUR'); somePLNs.add(someEuros);
  • 112. class Money constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs: Money<string> = new Money(100, 'PLN'); const someEuros = new Money(100, 'EUR'); somePLNs.add(someEuros); <T e e e e e e e e e e e e e > >
  • 113. class Money constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs: Money<string> = new Money(100, 'PLN'); const someEuros = new Money(100, 'EUR'); somePLNs.add(someEuros);
  • 114. class Money constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs: Money<string> = new Money(100, 'PLN'); const someEuros = new Money(100, 'EUR'); somePLNs.add(someEuros); <in out T extends string> {
  • 115. class Money constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs: Money<string> = new Money(100, 'PLN'); const someEuros = new Money(100, 'EUR'); somePLNs.add(someEuros); <in out T extends string> {
  • 116. class Money constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs: Money<string> = new Money(100, 'PLN'); const someEuros = new Money(100, 'EUR'); somePLNs.add(someEuros); <in out T extends string> {
  • 117. class Money constructor( public amount: number, public currency: T, ) {} add(money: Money<T>): Money<T> { return new Money(this.amount + money.amount, this.currency); } } const somePLNs = new Money(100, 'PLN' as string); const someEuros = new Money(100, 'EUR' as string); somePLNs.add(someEuros); <T extends string> { <in out T extends string> {
  • 118. A co z Functional Programming?
  • 119.
  • 120.
  • 121.
  • 123.
  • 124.
  • 125.
  • 126.
  • 132. Case study 1: 🪪 ID encji
  • 133.
  • 134. function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... }
  • 135. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... }
  • 136. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string;
  • 137. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', );
  • 139. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', );
  • 140. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', ); type UserId = string & { _type: 'user_id' };
  • 141. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', ); type UserId = string & { _type: 'user_id' }; type BookId = string & { _type: 'book_id' };
  • 142. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', ); type UserId = string & { _type: 'user_id' }; type BookId = string & { _type: 'book_id' };
  • 143. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', ); type UserId = string & { _type: 'user_id' }; type BookId = string & { _type: 'book_id' };
  • 144. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', ); type UserId = string & { _type: 'user_id' }; type BookId = string & { _type: 'book_id' };
  • 145. type UserId = string; function addBookToUserFavorites(userId: UserId, bookId: BookId) { // ... } type BookId = string; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962', 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2', ); type UserId = string & { _type: 'user_id' }; type BookId = string & { _type: 'book_id' }; addBookToUserFavorites( '716fccd0-73fd-4fbf-be44-7c3176242962' as UserId, 'a2db2ce5-6ad3-4b01-8f7e-8f435d9d30b2' as BookId, );
  • 146. type UserId = string & { _type: 'user_id' };
  • 147. type UserId = string & { _type: 'user_id' };
  • 148. type UserId = string & { _type: 'user_id' }; type Property = keyof any;
  • 149. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string
  • 150. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string object['_type']
  • 151. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string object['_type'] | number
  • 152. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string object['_type'] | number array[0]
  • 153. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string object['_type'] | number array[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
  • 154. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string object['_type'] | number array[0]
  • 155. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string object['_type'] | number array[0] | symbol
  • 156. type UserId = string & { _type: 'user_id' }; type Property = keyof any; | string object['_type'] | number array[0] | symbol object[Symbol('a')] = 'a';
  • 159. type UserId = string & { _type: 'user_id' };
  • 160. type UserId = string & { _type: 'user_id' }; declare const Nominal: unique symbol;
  • 161. type UserId = string & { _type: 'user_id' }; declare const Nominal: unique symbol; type UserId = string & { [Nominal]: 'user_id' };
  • 162. type UserId = string & { _type: 'user_id' }; declare const Nominal: unique symbol; type UserId = string & { [Nominal]: 'user_id' }; type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal };
  • 163. type UserId = string & { _type: 'user_id' }; declare const Nominal: unique symbol; type UserId = string & { [Nominal]: 'user_id' }; type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal }; type UserId = NominalType<string, 'user_id'>
  • 164. type UserId = string & { _type: 'user_id' }; declare const Nominal: unique symbol; type UserId = string & { [Nominal]: 'user_id' }; type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal }; type UserId = NominalType<string, 'user_id'> type BookId = NominalType<string, 'book_id'>
  • 165.
  • 170. Backend Frontend Kontrakt GET /books { id: BookId }[] POST /favorites { id: BookId }
  • 172. async function delayedHelloWorld() { await delay(1000); console.log('Hello World'); } const delay = (timeInterval: number) => new Promise( resolve => setTimeout(resolve, timeInterval) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 173. type TimeInterval = NominalType<number, 'TimeInterval'>;
  • 174. type TimeInterval = NominalType<number, 'TimeInterval'>; const milliseconds = (howMany: number) => howMany as TimeInterval; const seconds = (howMany: number) => (howMany * 1000) as TimeInterval;
  • 175. type TimeInterval = NominalType<number, 'TimeInterval'>; const milliseconds = (howMany: number) => howMany as TimeInterval; const seconds = (howMany: number) => (howMany * 1000) as TimeInterval; const toMilliseconds = (timeInterval: TimeInterval) => timeInterval as number; const toSeconds = (timeInterval: TimeInterval) => timeInterval / 1000;
  • 176. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, toMilliseconds(timeInterval)) );
  • 177. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, toMilliseconds(timeInterval)) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 178. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, toMilliseconds(timeInterval)) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 179. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, toMilliseconds(timeInterval)) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); }
  • 180. const delay = (timeInterval: TimeInterval) => new Promise( resolve => setTimeout(resolve, toMilliseconds(timeInterval)) ); async function delayedHelloWorld() { await delay(1); console.log('Hello World'); } async function delayedHelloWorld() { await delay(seconds(1)); console.log('Hello World'); }
  • 181. Case study 3: 💵 Pieniądze
  • 182. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
  • 183. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Money<'EUR'>;
  • 184. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Money<'EUR'>; const somePLNs = moneyInPLN(100); const someEuros = moneyInEUR(100);
  • 185. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Money<'EUR'>; const somePLNs = moneyInPLN(100); const someEuros = moneyInEUR(100); const amount1: Money<'EUR'> = someEuros; const amount2: Money<'EUR'> = somePLNs;
  • 186. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Money<'EUR'>; const somePLNs = moneyInPLN(100); const someEuros = moneyInEUR(100); const amount1: Money<'EUR'> = someEuros; const amount2: Money<'EUR'> = somePLNs;
  • 187. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Money<'EUR'>; const somePLNs = moneyInPLN(100); const someEuros = moneyInEUR(100); const amount1: Money<'EUR'> = someEuros; const amount2: Money<'EUR'> = somePLNs;
  • 188. const amount1: Money<'EUR'> = someEuros; const amount2: Money<'PLN'> = somePLNs; const sum = amount1 + amount2;
  • 189. const amount1: Money<'EUR'> = someEuros; const amount2: Money<'PLN'> = somePLNs; const sum = amount1 + amount2; const sum = 1 + 1;
  • 190. const amount1: Money<'EUR'> = someEuros; const amount2: Money<'PLN'> = somePLNs; const sum = amount1 + amount2; const sum = 1 + 1; const sum = {} + {};
  • 191. const amount1: Money<'EUR'> = someEuros; const amount2: Money<'PLN'> = somePLNs; const sum = amount1 + amount2; const sum = 1 + 1; const sum = {} + {};
  • 192. const amount1: Money<'EUR'> = someEuros; const amount2: Money<'PLN'> = somePLNs; const sum = amount1 + amount2; const sum = 1 + 1; const sum = {} + {};
  • 193. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency };
  • 194. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; declare const Nominal: unique symbol; type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency };
  • 195. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; declare const Nominal: unique symbol; type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>;
  • 196. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; declare const Nominal: unique symbol; type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>; const sum = someEuros + somePLNs;
  • 197. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; declare const Nominal: unique symbol; type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>; const sum = someEuros + somePLNs;
  • 198. declare const Nominal: unique symbol; type Money<TCurrency extends string> = number & { [Nominal]: TCurrency }; declare const Nominal: unique symbol; type Money<TCurrency extends string> = Number & { [Nominal]: TCurrency }; const moneyInPLN = (amount: number) => amount as Number as Money<'PLN'>; const moneyInEUR = (amount: number) => amount as Number as Money<'EUR'>; const sum = someEuros + somePLNs;
  • 199. function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney { return amount1 as any + amount2; }
  • 200. function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney { return amount1 as any + amount2; } const sum = addMoney(somePLNs, someEuros)
  • 201. function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney { return amount1 as any + amount2; } const sum = addMoney(somePLNs, someEuros)
  • 202. function addMoney<TMoney extends Money<string>>(amount1: TMoney, amount2: TMoney): TMoney { return amount1 as any + amount2; } const sum = addMoney(somePLNs, someEuros)
  • 204. Typowanie strukturalne + OO bywa pułapką
  • 205. Typowanie strukturalne + OO bywa pułapką user1.addFavoriteBook(user1);
  • 206. Możliwa jest symulacja typów nominalnych w TS
  • 207. Możliwa jest symulacja typów nominalnych w TS declare const Nominal: unique symbol;
  • 208. Możliwa jest symulacja typów nominalnych w TS declare const Nominal: unique symbol; type NominalType<TType, TNominal extends string> = TType & { [Nominal]: TNominal };
  • 209. Możemy dodać prymitywnym typom nominały
  • 210. Możemy dodać prymitywnym typom nominały type UserId = NominalType<string, 'user_id'> type BookId = NominalType<string, 'book_id'>
  • 211. Case study z pieniędzmi to być może nie najlepsze zastosowanie,
  • 212. Case study z pieniędzmi to być może nie najlepsze zastosowanie, ale warto wiedzieć że w TS istnieje masa sztuczek ;-)
  • 213. Case study z pieniędzmi to być może nie najlepsze zastosowanie, ale warto wiedzieć że w TS istnieje masa sztuczek ;-) Enkapsulacja operacji na prymitywnych typach
  • 214. Case study z pieniędzmi to być może nie najlepsze zastosowanie, ale warto wiedzieć że w TS istnieje masa sztuczek ;-) Enkapsulacja operacji na prymitywnych typach Opaque types
  • 215. Typy nominalne mogą czuwać nad liczbami i jednostkami
  • 216. Typy nominalne mogą czuwać nad liczbami i jednostkami async function delayedHelloWorld() { await delay(seconds(1)); console.log('Hello World'); }
  • 217. Typy nominalne mogą czuwać nad liczbami i jednostkami async function delayedHelloWorld() { await delay(seconds(1)); console.log('Hello World'); } Prymitywne typy pod spodem
  • 218. Typy nominalne mogą czuwać nad liczbami i jednostkami async function delayedHelloWorld() { await delay(seconds(1)); console.log('Hello World'); } Prymitywne typy pod spodem Terser?
  • 219. Typy nominalne mogą czuwać nad liczbami i jednostkami async function delayedHelloWorld() { await delay(seconds(1)); console.log('Hello World'); } Prymitywne typy pod spodem Terser? Inlining przy kompilacji
  • 220. Typy nominalne mogą czuwać nad liczbami i jednostkami async function delayedHelloWorld() { await delay(seconds(1)); console.log('Hello World'); } Prymitywne typy pod spodem Terser? Inlining przy kompilacji async function delayedHelloWorld() { await delay(1000); console.log('Hello World'); }
  • 221.
  • 222.
  • 223. Dziękuje za uwagę! Wiktor Toporek Senior Frontend Developer ✉ wiktor.toporek@tsh.io Twitter: @vViktorPL tsh.io ✉ wtoporek@gmail.com tsh.io/programowanko
  • 224. Dziękuje za uwagę! Wiktor Toporek Senior Frontend Developer ✉ wiktor.toporek@tsh.io Twitter: @vViktorPL tsh.io Q & A ✉ wtoporek@gmail.com tsh.io/programowanko