import "stream-chat";
import type { DefaultChannelData } from "stream-chat-react";
declare module "stream-chat" {
interface CustomChannelData extends DefaultChannelData {}
interface CustomMessageData {
custom_property?: string;
}
interface CustomUserData {
profile_picture?: string;
}
interface CustomCommandData {
"custom-command": unknown;
"other-custom-command": unknown;
}
}TypeScript & Custom Data Types
Both stream-chat-react and stream-chat have full TypeScript support.
They provide type safety, but also allow integrator-defined typings to be taken into consideration when working with Stream entities such as message or channel through the use of module augmentation (declaration merging).
There are twelve extendable interfaces in stream-chat, which merge with the base types of Stream entities:
CustomAttachmentDataCustomChannelDataCustomCommandDataCustomEventDataCustomMemberDataCustomMessageDataCustomPollOptionDataCustomPollDataCustomReactionDataCustomUserDataCustomThreadDataCustomMessageComposerData
Best Practices
- Use module augmentation to keep custom data types centralized.
- Extend
DefaultChannelDataif you rely on the default channel display helpers or channel-avatar related UI. - Keep custom types minimal to avoid bloated payloads.
- Regenerate or re-check types after SDK upgrades.
- Use
unknownfor command payloads when only keys matter.
Note that CustomChannelData is extended within stream-chat-react with commonly used fields (subtitle, image, name) in DefaultChannelData. Extending your declarations with these defaults (see below) isn’t required, but some default helpers and avatar-related channel UI still expect image and name to have the usual shapes. The default ChannelHeader no longer renders subtitle, so that field is only relevant if your own app code or custom components use it.
Declare Custom Data Types
To extend these custom interfaces you'll have to create a declaration file within your codebase and make sure it's loaded by the TypeScript. Within this file we'll import stream-chat and specific defaults from stream-chat-react and then define the interface augmentations:
Note that CustomCommandData interface is a special case from which only the keys would be used, the value type is not important and unknown would suffice.
That's it, you can check if your augmentations work with similar code:
import { StreamChat } from "stream-chat";
const client = new StreamChat("any-key");
const response = await client.getMessage("id");
const customProperty = response.message.custom_property; // should be `string | undefined` as per our declaration