Skip to main content

TypeScript and Generics

As of version 5.0.0, stream-chat-react has been converted to TypeScript. The stream-chat library was converted to TypeScript in version 2.0.0. These upgrades not only improve type safety, but also allow user provided typings to be passed to server requests and custom components through the use of generics.

In many cases, TypeScript uses inference from provided props to establish a component or value's type. It is therefore important that the proper generics be applied to the stream-chat client instance during construction. The documentation on stream-chat TypeScript has detailed examples of how this can be accomplished. The Stream Chat client takes seven optional generics that correspond to the seven customizable fields that currently exist in stream-chat.

const client = StreamChat.getInstance<  AttachmentType,  ChannelType,  CommandType,  EventType,  MessageType,  ReactionType,  UserType>('YOUR_API_KEY');

The seven customizable fields these generics extend are provided via stream-chat:

  1. Attachment
  2. ChannelResponse
  3. CommandVariants
  4. Event
  5. MessageBase
  6. Reaction
  7. User

All seven generics contain defaults in the component library that can be extended for custom data. Additional fields on the defaults (ex: file_size, mime_type, and image) are added by stream-chat-react within the SDK. When adding to the subset of generics, the preceding and interceding generics must also be set in order for the TypeScript compiler to correctly understand intent.

The below example shows how to extend ChannelType, MessageType, and UserType during client instantiation:

const client = StreamChat.getInstance<  DefaultAttachmentType,  { image?: string },  DefaultCommandType,  DefaultEventType,  { isAdminMessage?: boolean },  DefaultReactionType,  { nickName?: string }>('YOUR_API_KEY');

Through this client instantiation, we have added type support for the following values:

  • channel.image
  • message.isAdminMessage
  • user.nickName
note

DefaultCommandType extends string & {} to maintain intellisense for the included commands. This allows you to extend a string union.

The below snippet shows the current default types in the stream-chat-react component library. Any additional custom types will extend these defaults. Core to understanding this pattern is how generics can be applied to JSX elements.

type DefaultAttachmentType = Record<string, unknown> & {  asset_url?: string;  file_size?: number;  id?: string;  images?: Array<{    image_url?: string;    thumb_url?: string;  }>;  mime_type?: string;};
type DefaultChannelType = Record<string, unknown> & {  image?: string;  member_count?: number;  subtitle?: string;};
type DefaultCommandType = string & {};
type DefaultEventType = Record<string, unknown>;
type DefaultMessageType = Record<string, unknown> & {  customType?: 'channel.intro' | 'message.date';  date?: string | Date;  errorStatusCode?: number;  event?: Event<    DefaultAttachmentType,    DefaultChannelType,    DefaultCommandType,    DefaultEventType,    DefaultMessageType,    DefaultReactionType,    DefaultUserType  >;  unread?: boolean;};
type DefaultReactionType = Record<string, unknown>;
export type DefaultUserTypeInternal = {  image?: string;  status?: string;};
export type DefaultUserType<  UserType extends DefaultUserTypeInternal = DefaultUserTypeInternal> = UnknownType &  DefaultUserTypeInternal & {    mutes?: Array<Mute<UserType>>;  };

The exported custom context hooks also require generics be applied to correctly type custom returns. For example, the useChannelStateContext hook needs all generics to get a correctly typed return for channel.

const { channel } = useChannelStateContext<  DefaultAttachmentType,  { image?: string },  DefaultCommandType,  DefaultEventType,  { isAdminMessage?: boolean },  DefaultReactionType,  { nickName?: string }>();
tip

To see an example of extending the default Attachment type, see the Geolocation Attachment custom code example.

Did you find this page helpful?