Types
Every value in ts2 has a type, and types that look alike cannot be swapped.
Value types
Section titled “Value types”The basic three:
| Type | |
|---|---|
Int | A whole number. There is no floating point anywhere. |
String | Text. |
Boolean | True or false. |
Everything else names a kind of game thing. Each is a whole number underneath, and none can be substituted for another:
| Type | |
|---|---|
Sprite | An image |
Font | A font |
Item | An item |
ItemName | An item named for display rather than held. Reads the same parameters an Item does |
ItemId | An item’s number where the game keeps it apart from the item itself |
Model | A 3D model |
Animation | An animation |
Texture | A texture |
Sound | A sound |
Npc | A kind of NPC |
NpcInstance | One NPC standing in the world, rather than its kind |
WorldObject | A kind of world object |
WorldObjectShape | The shape a world object takes |
EntityOverlay | An overlay drawn over something in the world |
Skill | A skill |
Inventory | A container, named |
Enum | One of the game’s tables, as a value |
Struct | One of the game’s rows, as a value. A Row is one of these |
DbTable, DbRow, DbColumn | A table, a row and a column of the game’s database |
VarPlayer | A game variable, named |
ComponentId | A component, by address |
Interface | An interface |
RootInterface | The frame an interface opens into |
Coord | A world position. Has .x, .z and .plane |
Area | A named area of the world |
MapIcon | An icon on the world map |
WorldMapId | One of the world maps |
ContentCategory | A category the game sorts content by |
Char | A single character. A key press carries one |
IntArray, StringArray, AnyIntArray | An array the game hands over. See collections |
Long | A 64-bit whole number. Carried, never computed with |
Values of these types come from the generated dictionaries.
A read that can miss
Section titled “A read that can miss”.at(i) on a list and .get(k) on a map answer Value | null, unless the
index or key is a literal, a const bound to one, or a member of an enum.
const categoryLabel = (names: Map<Category, String>, ware: Ware): String => names.get(ware.category) ?? 'Sundries';const Special = ({ i }: { i: Int }): Component => { const ware = WARES.at(i); if (ware === null) { return null; } return ( <text x={0} y={0} w="fill" h={16} text={`Special: ${ware.name}, ${ware.price} gp`} font={Fonts.PLAIN} valign="middle" shadow color={Colors.YELLOW} /> );};Two ways to discharge it, and the value’s kind picks one. A number or a
string takes ??, which names what a miss should read as. A record takes
=== null. === null is the one comparison against something that is not a
number. See Declaring your own data.
WARES.at(1 + 1) is Ware | null. Write WARES.at(2), or discharge the
read.
Reference types
Section titled “Reference types”| Type | Carries |
|---|---|
VarpRef<Id, Type> | A game variable, and what it holds — a plain number unless the dictionary says 'item' or another kind |
VarbitRef<Id, Base, Type> | A field inside a game variable, which variable contains it, and what it holds |
SkillRef<Id> | A skill |
InvRef<Id, Size> | A container, and how many slots it has |
ListRef<Id, Length, Value> | One of the game’s tables whose keys are positions, how many entries it has, and their type |
MapRef<Id, Rows, Key, Value, FirstKey> | One of the game’s tables read by key: its row count, the types of its keys and values, and the key its rows start at |
ParamRef<Id, Type> | A named parameter of an item, an NPC, a world object or a row, and the type of value it holds |
StructRef<Id> | One of the game’s rows, named outright. Reads exactly as a Row does |
You do not write these. The dictionaries declare them, and you alias what you use:
export declare const SlotIcons: typeof GameEnums.ENUM_904;export declare const SkillIcons: typeof GameEnums.ENUM_255;A ListRef reads as a List and a MapRef as a Map; the
collections page has both in full.
Handle types
Section titled “Handle types”Component
Section titled “Component”The type of markup. A function returning Component is a
component. It may return null
to draw nothing:
const Slot = ({ item, count, slot }: { item: Item; count: Int; slot: Int }): Component => (The return type of a function that declares an interface:
export const waresUi = (): UI => ( <ui ref={waresRef} w={252} h={376}> <Wares /> </ui>);The same as a Component, except a UI may not be null.
Children
Section titled “Children”Markup passed to a component between its tags. See Composing components.
export const SunkenBox = ({ children }: { children?: Children }): Component => (What a handler receives as its parameter — which component fired, which option
was chosen, where the mouse is. It cannot be stored, passed or returned. Every field is on
Event.
Handler and Callback
Section titled “Handler and Callback”A Handler is what an event prop takes: an arrow function, written in place or
named, taking the event or nothing. A Callback is a Handler or null, and
null is how a handler is taken off a component that already has one — through
a ref, or on one arm of a conditional. See
Events.
content.onScrollWheel = (event) => {A named handler is not a value: it cannot be passed to a function, returned from one, or stored in state.
Option
Section titled “Option”One right-click option, when a plain string is not enough. label is the menu
text, hotkey a key code (Escape is 13), modifiers a mask — 1 for ctrl, 2 for
alt, 4 for shift. An empty label with a hotkey is a keyboard-only option. See
Hover and menus.
A handle to one component. Its writable properties are the props of the
element it is bound to; props writes several at once, options writes the
menu; width, height, x, y, scrollX and scrollY can be read back.
Declared with useRef inside a render or
createRef at module scope. See Refs.
ComponentId
Section titled “ComponentId”A component by address — what event.component is, and what a component
declares to take a component from anywhere, not only one its caller built.
A Ref passes where a ComponentId is wanted. Reading geometry through one
takes a ! (target.width!).
A world position, read back axis by axis: .x is east–west, .z is
north–south, .plane is the floor. Made with
tileOf:
const LUMBRIDGE = tileOf(3222, 3218, 0); text={`Lumbridge: ${LUMBRIDGE.x}, ${LUMBRIDGE.z}, ${LUMBRIDGE.plane === 0 ? 'ground floor' : `floor ${LUMBRIDGE.plane}`}`}Row and StructRef
Section titled “Row and StructRef”One row of a table the game ships. Its fields are parameters, read by naming them:
row.int(param): Int — a whole-number parameter, typed by the parameter's own kindrow.text(param): String — a text parameterrow.sprite(param): Sprite — a sprite parameterA Row is also a Struct, so it can be passed to a component that declares
one. A StructRef<Id> is a row named outright in a dictionary, and reads the
same way. A record type you
declared yourself is not a Row — its
fields are ordinary properties, ware.price.
Container
Section titled “Container”What useInventory returns: the
items in a container, by slot. Its accessors are on the
collections page.
List<Value> and Map<Key, Value>
Section titled “List<Value> and Map<Key, Value>”A collection you declared with listOf or mapOf, or one of the game’s tables
through a ListRef or MapRef. Both are ordinary values: a List<Int> can be
a prop, a parameter, a return type or another map’s value type. Everything they
do is on the collections page.
StateRef<T> and Setter<T>
Section titled “StateRef<T> and Setter<T>”A state declaration, and the function that writes it. sessionState and
persistedState return a StateRef; useState returns the value and a
Setter. See useState.
What useInterval and useDelay return. One method, stop(). See
Timers.
Geometry types
Section titled “Geometry types”The types behind x, y, w and h, as the language declares them:
type XPosition = | Int | 'left' | 'center' | 'right' | `${number}%` | { left: Offset } | { center: Offset } | { right: Offset };
type YPosition = | Int | 'top' | 'center' | 'bottom' | `${number}%` | { top: Offset } | { center: Offset } | { bottom: Offset };
type Offset = Int | `${number}%`;
type Extent = | Int | 'fill' | 'aspect' | `${number}%` | { fill: Offset };A position anchor’s offset may be a pixel count or a proportion of the parent:
{ right: 4 } is four pixels in from the right edge, { center: '25%' } is
centred and then moved a quarter of the parent’s width. { left: '25%' } means
the same as the bare "25%".
<sprite x={{ left: '15%' }} y="center" w={36} h={32} item={Items.RUNE_SCIMITAR} itemCount={-1} /><sprite x="center" y="center" w={36} h={32} item={Items.AMULET_OF_POWER} itemCount={-1} /><sprite x={{ right: '15%' }} y="center" w={36} h={32} item={Items.LOBSTER} itemCount={5} />A size anchor takes a pixel count only. { fill: 8 } is the parent less
eight; w="10%" is a tenth of it; { fill: '10%' } is refused (TS2E210):
{/* refused: */} <rect x={10} y={42} w={{ fill: '10%' }} h={16} color={Colors.AMBER} fill />An anchored value takes exactly one anchor: { left: 3, right: 3 } is refused
too. A keyword or a percentage kept in a constants object needs as const, or
the prop sees a string (TS2322): const Layout = { HALF: '50%' as const };. Layout and geometry shows every form on
screen.
Alignment and modes
Section titled “Alignment and modes”type Align = 'left' | 'center' | 'right';type VAlign = 'top' | 'middle' | 'bottom' | 'even';type ItemCountMode = 'auto' | 'never' | 'always';valign="even" shares the leftover height of a multi-line text into equal gaps
— one above the first line, one between each pair, one below the last — and is
the same as middle on a single line. There is no horizontal even.
itemCountMode says whether an item slot draws its stack size: auto only for
an item that stacks, never and always regardless. It is independent of
itemCount, which is the quantity itself.
type ContentType = | 'fpsCounter' | 'worldView' | 'minimap' | 'compass' | 'worldMap' | 'worldMapOverview' | 'loginRunes' | Int;contentType marks a component as one of the surfaces the client draws itself
— the 3D world, the minimap, the world map. A number is accepted for a surface
the client does not name.
Declaring types of your own
Section titled “Declaring types of your own”Declare the type of a component’s props:
const PrayerCell = ({ prayer, unlocked, x, y }: { prayer: Prayer; unlocked: Boolean; x: Int; y: Int;}): Component => (Declare a record type for the rows of a collection:
type Prayer = { name: String; level: Int; icon: Sprite;};An enum declares a set of
named whole numbers, and is always a constant.
There are no classes, no generics of your own, and no unions beyond string
literals and | null.
Troubleshooting
Section titled “Troubleshooting””Int is not assignable to Sprite”
Section titled “”Int is not assignable to Sprite””A prop declared as a plain number cannot be passed to something expecting a
sprite. Declare the prop with the type it actually holds — icon: Sprite, not
icon: Int.
”Object is possibly ‘null’”
Section titled “”Object is possibly ‘null’””You read a collection with an index or key that is not a literal, and used the
result without saying what a miss should give. Add ?? fallback for a number
or a string; test === null and return null for a record. See
A read that can miss.
My division is wrong by one
Section titled “My division is wrong by one”Arithmetic is whole-number, and division truncates. 7 / 2 is 3, not 3.5.
To round up, add the divisor less one first: (n + 7) / 8.