Skip to main content

Type System

Skittles maps TypeScript types to Solidity types at compile time. This page covers every supported type and how it translates.

Primitive Types

TypeScriptSolidityNotes
numberuint256All numbers are unsigned 256 bit integers
stringstringUTF-8 strings
booleanbooltrue / false
class Example {
count: number = 0; // uint256 public count;
name: string = "hello"; // string public name = "hello";
active: boolean = true; // bool public active = true;
}

Ethereum Types

Import address and bytes from "skittles":

import { address, bytes } from "skittles";

class Example {
owner: address = msg.sender; // address public owner;
data: bytes = ""; // bytes public data;
}
TypeScriptSolidity
addressaddress
bytesbytes

Address literals (42 character hex strings starting with 0x) are automatically wrapped in address(...):

// TypeScript
const zero: address = "0x0000000000000000000000000000000000000000";

// Generates: address(0x0000000000000000000000000000000000000000)

Mappings

Use Record<K, V> to create Solidity mappings:

import { address } from "skittles";

class Token {
balances: Record<address, number> = {};
// mapping(address => uint256) public balances;

allowances: Record<address, Record<address, number>> = {};
// mapping(address => mapping(address => uint256)) public allowances;
}

Nested Record types create nested mappings. This is commonly used for ERC20 allowances.

Arrays

Use T[] for dynamic arrays:

class Example {
owners: address[] = [];
// address[] public owners;

values: number[] = [];
// uint256[] public values;
}

Array methods push() and pop() are supported:

this.owners.push(newOwner);
this.owners.pop();

Array .length is accessible for iteration:

for (let i: number = 0; i < this.owners.length; i++) {
// ...
}

Structs

TypeScript interfaces compile to Solidity structs:

contracts/types.ts
import { address } from "skittles";

export interface StakeInfo {
amount: number;
timestamp: number;
account: address;
}
Generated Solidity
struct StakeInfo {
uint256 amount;
uint256 timestamp;
address account;
}

Struct instances are created with object literals:

let info: StakeInfo = {
amount: this.deposits[account],
timestamp: this.depositTimestamps[account],
account: account,
};
return info;

Structs can be shared across contract files. See Cross File Support.

Enums

TypeScript enums compile to Solidity enums:

contracts/types.ts
export enum VaultStatus {
Active,
Paused,
}
Generated Solidity
enum VaultStatus { Active, Paused }

Use them as state variable types and in comparisons:

class Staking {
public status: VaultStatus;

public pause(): void {
this.status = VaultStatus.Paused;
}

private _requireActive(): void {
if (this.status == VaultStatus.Paused) {
throw this.VaultPaused();
}
}
}

Enums can be shared across contract files. See Cross File Support.

Type Inference

Local variables inside functions can omit explicit types when the type can be inferred:

transfer(to: address, amount: number): boolean {
const sender = msg.sender; // inferred as address
const balance = this.balances[sender]; // inferred as uint256
const valid = amount > 0; // inferred as bool
// ...
}

The compiler infers types from:

  • Literal values: numbers → uint256, strings → string, booleans → bool
  • msg.senderaddress, msg.valueuint256
  • block.timestamp, block.numberuint256
  • Property access on this → the type of the state variable
  • Mapping/array access → the value type of the mapping/array
  • Comparison operators → bool

Function parameters and return types must always be explicitly typed.

Void

Functions that return nothing use void:

transfer(to: address, amount: number): void {
// No return statement needed
}

This generates a Solidity function with no returns clause.