TypeScript
itty-sockets is fully typed out of the box. Types adjust automatically based on your connection, and you can add strictness incrementally — from a single listener up to a fully typed event map.
Automatic Protocol Detection
When you connect to a channel name, itty-sockets automatically types the connection with the itty protocol — join, leave, and error events, plus uid, alias, and date on messages.
No generic needed.
import { connect } from 'itty-sockets'
// itty protocol is the default — no generic needed
const channel = connect('my-channel')
// join/leave/error events are fully typed
channel.on('join', ({ users, uid, alias }) => {
// users: number, uid/alias: optional strings
})
// messages include uid, alias, and date
channel.on('message', ({ message, uid, date }) => {
// uid: string, date: number
})When you connect to a wss:// or ws:// URL, itty-sockets detects that it's a custom server and strips those itty-specific types automatically.
import { connect } from 'itty-sockets'
// wss:// URLs are auto-detected as custom servers
// no join/leave/error events, no uid/date on messages
const ws = connect('wss://my-server.com/ws')
ws.on('open', () => { /* connected */ })
ws.on('message', ({ message }) => { /* raw message */ })Typing Listeners
Pass a generic to .on() to type an individual listener's payload.
The generic is intersected with the base protocol, so you still get uid, date, etc.
type ChatMessage = { type: 'chat', text: string, user: string }
type MoveMessage = { type: 'move', x: number, y: number }
const channel = connect('my-app')
// type individual listeners with a generic
channel.on<ChatMessage>('chat', ({ text, user, uid }) => {
// text: string, user: string — from ChatMessage
// uid: string — from the itty protocol
})
channel.on<MoveMessage>('move', ({ x, y }) => {
// x: number, y: number
})Typing Sends
Similarly, pass a generic to .send() to type an individual send.
Useful when you send different message shapes from different places in your code.
type ChatMessage = { type: 'chat', text: string, user: string }
const channel = connect('my-app')
// type individual sends with a generic
channel.send<ChatMessage>({ type: 'chat', text: 'hello', user: 'Alice' })
channel.send<ChatMessage>({ type: 'chat' }) // TS error — missing text, userEvent Maps
For full type safety across an entire connection, pass an event map as the generic to connect().
This types both listeners and sends — listeners are auto-typed by event name, and sends must include a type field matching a key in the map.
import { connect } from 'itty-sockets'
type MyEvents = {
chat: { text: string, user: string }
move: { x: number, y: number }
}
const channel = connect<MyEvents>('my-app')
// listeners are auto-typed by event name
channel.on('chat', ({ text, user, uid, date }) => {
// text, user — from event map
// uid, date — from itty protocol
})
// sends require { type } matching an event key
channel.send({ type: 'chat', text: 'hello', user: 'Alice' }) // ✓
channel.send({ type: 'move', x: 1, y: 2 }) // ✓
channel.send({ type: 'chat' }) // ✗ missing fieldsEvent maps work on custom servers too — the only difference is that itty protocol fields (uid, date) won't be present.
Untyped Sends
By default, an event map only allows sends that match a defined event.
To also allow untyped sends (strings, arrays, plain objects), add a message key to your map:
type MyEvents = {
chat: { text: string, user: string }
message: string | number[] // allows untyped sends
}
const channel = connect<MyEvents>('my-app')
channel.send({ type: 'chat', text: 'hi', user: 'Alice' }) // ✓ typed
channel.send('hello') // ✓ untyped
channel.send([1, 2, 3]) // ✓ untypedExported Types
All types are exported from the package for use in your own code:
import type {
IttyProtocol, // base fields for itty.ws (uid, alias, date)
IttySocket, // the socket instance type
IttySocketOptions, // { as?, alias?, echo?, announce? }
JoinEvent, // { type, users, uid?, alias?, date }
LeaveEvent, // { type, users, uid?, alias?, date }
ErrorEvent, // { type, message, date }
MessageEvent, // { message, uid?, alias?, date }
} from 'itty-sockets'Next: Namespaces — reserve a prefix and control access to your channels.