Supporters
JOIN MY SPONSORS

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.

itty-default.ts
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.

custom-server.ts
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.

on-generic.ts
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.

send-generic.ts
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, user

Event 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.

event-map.ts
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 fields

Event 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:

event-map-message.ts
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])                                      // ✓ untyped

Exported Types

All types are exported from the package for use in your own code:

types.ts
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.