-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path9-generics.ts
More file actions
85 lines (67 loc) · 2.01 KB
/
9-generics.ts
File metadata and controls
85 lines (67 loc) · 2.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// Parametric polymorphism with Generics
interface Account {
id: string;
balance: number;
}
interface SavingsAccount extends Account {
kind: 'savings';
rate: number;
}
interface CreditAccount extends Account {
kind: 'credit';
limit: number;
}
type AnyAccount = SavingsAccount | CreditAccount;
type TransactionKind = 'deposit' | 'withdraw';
interface Transaction<T extends Account> {
kind: TransactionKind;
amount: number;
}
function applyTransaction<T extends Account>(account: T, tx: Transaction<T>): T {
if (tx.amount < 0) throw new Error('Amount must be non-negative');
if (tx.kind === 'withdraw' && account.balance < tx.amount) {
throw new Error('Insufficient funds');
}
const balance = tx.kind === 'deposit'
? account.balance + tx.amount
: account.balance - tx.amount;
return { ...account, balance };
}
class Ledger<T extends Account> {
private entries: Array<{ accountId: string; kind: TransactionKind; amount: number }>;
constructor() {
this.entries = [];
}
record(account: T, tx: Transaction<T>): T {
const updated = applyTransaction(account, tx);
const { kind, amount } = tx;
const record = { accountId: account.id, kind, amount };
this.entries.push(record);
return updated;
}
getAll() {
return this.entries.slice();
}
}
// Usage
const savings: SavingsAccount = {
id: 'S-1',
balance: 1000,
kind: 'savings',
rate: 0.02,
};
const credit: CreditAccount = {
id: 'C-1',
balance: 0,
kind: 'credit',
limit: 2000,
};
const ledgerSavings = new Ledger<SavingsAccount>();
const ledgerCredit = new Ledger<CreditAccount>();
const s1 = ledgerSavings.record(savings, { kind: 'deposit', amount: 200 });
const s2 = ledgerSavings.record(s1, { kind: 'withdraw', amount: 50 });
const c1 = ledgerCredit.record(credit, { kind: 'deposit', amount: 500 });
const c2 = ledgerCredit.record(c1, { kind: 'withdraw', amount: 150 });
console.dir({ s2, c2 });
console.log('Savings entries:', ledgerSavings.getAll());
console.log('Credit entries:', ledgerCredit.getAll());