| TypeScript Notation | Our Notation |
|---|---|
{ name: string, age: number, [otherField: string]: boolean } | name → string age → number otherField → boolean |
| string[] | index → string |
function doubleNum(x) { return x * 2 } let y = doubleNum(5) | function doubleNum(x) { return x * 2 } let y = doubleNum(5) |
These examples all run through our interpreter! You can modify them by scrolling down.
Simple Example A simple example you can play around with. | function fibonacci(n: number): number { if (n <= 1) {return n}return fibonacci(n - 1) + fibonacci(n - 2) } let z = fibonacci(5) |
Substitution Complication #1: We need to parameterize inlined function call arguments so that the expansion doesn't show redundant function calls. | function twoTimesNum(x: number) { return x * 2 } function squareNum(x: number) { return x * x } let z = squareNum(twoTimesNum(5)) |
Closures Complication #2: Closures with implicit dependencies. We track implicit parameters and show them clearly when you expand them. | let taxRate = 0.2let addTax = (price: number) → {return price + price * taxRate}return addTax(100) |
Limitations Complication #3: It's NP-hard to track the narrowest possible types of first-class functions with implicit parameters, like f here. TS itself does not do this at all, and this is the reason why TS itself with async/await type checking. We have no solution to this case, but are OK with this, because it is relatively rare and impossible to solve in general. | type User = name → string age → number function doThingsToUser(user: User, ...fns: index → (User)→undefined for (const f of fns) {f(user)} } function setUserName(user: User) { user.name = 'Bob' } let user = { name: 'Max', age: 99 } doThingsToUser(user, setUserName) |