# 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)](https://www.typescriptlang.org/docs/handbook/declaration-merging.html).

There are [twelve](https://github.com/GetStream/stream-chat-js/blob/fix/remove-stream-chat-generics/src/custom_types.ts) extendable interfaces in `stream-chat`, which merge with the base types of Stream entities:

1. `CustomAttachmentData`
2. `CustomChannelData`
3. `CustomCommandData`
4. `CustomEventData`
5. `CustomMemberData`
6. `CustomMessageData`
7. `CustomPollOptionData`
8. `CustomPollData`
9. `CustomReactionData`
10. `CustomUserData`
11. `CustomThreadData`
12. `CustomMessageComposerData`

## Best Practices

- Use module augmentation to keep custom data types centralized.
- Extend `DefaultChannelData` if 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 `unknown` for command payloads when only keys matter.

<admonition type="warning">

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.

</admonition>

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

```ts title="stream-custom-data.d.ts"
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;
  }
}
```

<admonition type="info">

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.

</admonition>

That's it, you can check if your augmentations work with similar code:

```ts
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
```


---

This page was last updated at 2026-05-22T16:32:14.143Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/guides/typescript-and-custom-data-types/](https://getstream.io/chat/docs/sdk/react/guides/typescript-and-custom-data-types/).