Independent Consultant & Software Architect
Trainer, Speaker, JS/TS Expert
ArchitekturaNaFroncie.pl (ANF)
Warsaw, PL
tomasz (at) ducin.dev
@tomasz_ducin
let productsCount = 12 // count
let unitPrice = 1.99 // money
productsCount = 13 // 👍
productsCount = unitPrice // 🤯
let discount = 0.99
productsCount -= discount // 🤯
unitPrice*unitPrice // 🤯
productsCount = unitPrice * discount // 🤯
type Money = number
let unitPrice: Money = 1.99
declare function totalPrice(
productPrice: Money,
productQuantity: number
): void
totalPrice(unitPrice, 12) // 👍
totalPrice(1.99, 12) // 🤯
declare const brand_symbol: unique symbol
type BrandType<BaseType, BrandName> = BaseType & {
readonly [brand_symbol]: BrandName
}
type Money = BrandType<number, "MONEY">
type DateString = BrandType<string, "DATE_STRING">
type EmailString = BrandType<string, "EMAIL">
let myAddress: EmailString = 'tomasz@ducin.it' // ❌
// Type 'string' is not assignable to type 'EmailString
const asEmail = (arg: string) => arg as EmailString
let myAddress: EmailString = asEmail('tomasz@ducin.it') // 👍
declare function sendEmail(email: EmailString): void;
let myAddress = 'tomasz@ducin.it' // string
sendEmail(myAddress) // ❌
// Type 'string' is not assignable to type 'EmailString'.
function isEmail(arg: string): arg is EmailString {
const regexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
return regexp.test(arg);
}
if (isEmail(myAddress)){
// inside: myAddress is EmailString
sendEmail(myAddress) // 👍
} // else: just a string
let some = {
amount: 19.99,
currency: "PLN"
}
let more = {
amount: 50,
currency: "USD"
}
let sum
if (some.currency == more.currency){
sum = {
amount: some.amount + more.amount,
currency: some.currency
}
}
class Money {
private constructor(
private amount: number,
private currency: string,
){}
static from(amount: number, currency: Currency){
return new Money(amount, currency)
}
nominalValue(){
return this.amount
}
//...
}
let money = Money.from(19.99, "PLN")
class Money {
private amount: number,
private currency: string,
//...
add(another: Money){
if (this.currency != another.currency){
throw new Error('Cannot add different currencies')
}
return new Money(this.amount + another.amount, this.currency)
}
multiply(factor: number){
return new Money(this.amount * factor, this.currency)
}
}
number, string, ...
type Money = number
type Money = BrandType<number, "MONEY">
class Money {
constructor(
private amount: number,
private currency: string,
){}
//...
}