Control Flow
Skittles supports all standard TypeScript control flow patterns. Use them exactly as you would in any TypeScript project.
If / Else
if (amount > 0) {
this.balances[to] += amount;
} else {
throw new Error("Invalid amount");
}
For Loops
Standard for loops:
for (let i: number = 0; i < this.owners.length; i++) {
this.balances[this.owners[i]] = 0;
}
For...of Loops
for...of loops work on arrays:
for (const owner of this.owners) {
this.balances[owner] = 0;
}
For...in Loops
for...in loops iterate over all values of an enum:
enum Status { Active, Paused, Stopped }
for (const status in Status) {
// Runs once for each enum member
}
The compiler desugars this into a standard indexed loop over the enum range.
While Loops
while (this.count > 0) {
this.count -= 1;
}
Do/While Loops
do {
this.count -= 1;
} while (this.count > 0);
Break and Continue
Both break and continue are supported inside loops:
for (let i: number = 0; i < this.owners.length; i++) {
if (this.owners[i] == target) {
break;
}
if (this.balances[this.owners[i]] == 0) {
continue;
}
// ...
}
Switch / Case
switch (status) {
case VaultStatus.Active:
this._processActive();
break;
case VaultStatus.Paused:
this._processPaused();
break;
default:
throw new Error("Unknown status");
}
Ternary Operator
The conditional (ternary) operator:
let result: number = amount > 0 ? amount : 0;
Void ternary expressions (used as statements for side effects) are also supported and compile to if/else:
condition ? this.doA() : this.doB();
Array Destructuring
Array destructuring is supported for local variable declarations:
const [a, b, c] = [7, 8, 9];
Conditional destructuring is also supported:
let [x, y] = condition ? [a, b] : [b, a];
Tuple Destructuring
You can destructure tuple return values from function calls:
const [r0, r1] = this.getReserves();
This compiles to Solidity's native tuple destructuring syntax: (uint256 r0, uint256 r1) = getReserves();
Object Destructuring
Object destructuring is supported for struct fields:
const { amount, timestamp } = this.getStakeInfo(account);
Direct object literal destructuring also works:
const { a, b } = { a: 1, b: 2 };
Delete
The delete operator resets values in your contract's storage (useful for clearing mapping entries):
delete this.balances[account];
You can also use the Map .delete() method:
this.balances.delete(account);
Try / Catch
Use try/catch to gracefully handle failures from external contract calls. The first statement in the try block must be an external contract call:
try {
const balance: number = this.token.balanceOf(account);
this.lastBalance = balance;
} catch (e) {
this.lastBalance = 0;
}
If the external call fails, execution jumps to the catch block. This is useful for composable DeFi protocols that need to handle failures in other contracts.
You can also use try/catch without capturing a return value:
try {
this.token.transfer(to, amount);
} catch (e) {
this.failed = true;
}