SlideShare une entreprise Scribd logo
1  sur  224
Télécharger pour lire hors ligne
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

Contenu connexe

Similaire à 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
 

Similaire à 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
 

Plus 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
 

Plus 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ć?
 

Dernier

Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Dernier (20)

Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

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