const client = StreamChat.getInstance<StreamChatGenerics>("YOUR_API_KEY");
Typescript
The stream-chat-react-native
as well as the client library stream-chat-js
are written in TypeScript and therefore provide full TypeScript support.
Stream Chat allows for a variety of customizations including custom fields on messages, channels, users, and more. The goal of the Stream Chat TypeScript implementation is to provide static type safety not just on out of the box Stream Chat implementation, but also on custom data provided to the API & SDK as well.
Generics
Generics allow users of the library to accurately represent custom data fields being used by providing typings that are passed to server responses, custom components, filters, etc. In many cases TypeScript can use inference from a provided prop to infer the generics used.
Client
It is important that the proper generics be applied to the stream-chat-js
client when it is instantiated.
The client a generic type that defines seven customizable fields that currently exist in stream-chat-js
.
where StreamChatGenerics
can be defined as a type with the seven generics that correspond to the seven customizable fields as follows:
type StreamChatGenerics = {
attachmentType: LocalAttachmentType;
channelType: LocalChannelType;
commandType: LocalCommandType;
eventType: LocalEventType;
messageType: LocalMessageType;
reactionType: LocalReactionType;
userType: LocalUserType;
};
LocalAttachmentType
, LocalChannelType
etc. are type definitions for their respective key as per your application types necessities.
Eg:
type LocalAttachmentType = {
file_size?: number;
mime_type?: string;
};
type LocalChannelType = Record<string, unknown>;
type LocalCommandType = string;
type LocalEventType = Record<string, unknown>;
type LocalMessageType = Record<string, unknown>;
type LocalReactionType = Record<string, unknown>;
type LocalUserType = {
image?: string;
};
The seven customizable fields these generics extend are provided via stream-chat-js
.
All seven generics contain defaults in the stream-chat-react-native
repository that you can extend for custom data such as custom types for Channels, Messages, etc.
type DefaultAttachmentType = Record<string, unknown>;
type DefaultChannelType = Record<string, unknown> & {
image?: string;
};
type DefaultCommandType = string & {};
type DefaultEventType = Record<string, unknown>;
type DefaultMessageType = Record<string, unknown>;
type DefaultReactionType = Record<string, unknown>;
type DefaultUserType = Record<string, unknown> & {
image?: string;
};
Additional fields on the defaults, for example image
, are custom fields used by stream-chat-react-native
already within the SDK.
When wanting to set a subset of generics, the preceding and interceding generics must also be set for the TypeScript compiler to understand intent correctly.
type StreamChatGenerics = {
attachmentType: DefaultAttachmentType;
channelType: DefaultChannelType;
commandType: DefaultCommandType;
eventType: DefaultEventType;
messageType: DefaultMessageType;
reactionType: DefaultReactionType;
userType: DefaultUserType;
};
const client = StreamChat.getInstance<StreamChatGenerics>("YOUR_API_KEY");
DefaultCommandType
is set to string & {}
instead of string
to maintain IntelliSense for the included commands.
In use a string union such as 'poll' | 'question'
could be used to extend them.
JSX / TSX
The TypeScript Example App shows how to apply the generics to many of the components in the SDK. Core to understanding this usage is how generics can be applied to JSX elements.
In many cases the use of a single prop such as client
or channel
allows TypeScript to infer the generics on an element.
In this case channelType
within StreamChatGenerics
is inferred from channel
and passed to the props type for a custom Attachment component.
Not all components use or are always provided a prop that can provide inference though.
In these cases the generics must be applied to the component directly.
MessageList
for instance could have the previous generics used on client
applied to it in a similar manner.
<MessageList<StreamChatGenerics>
onThreadSelect={(thread) => {
/** Set thread and navigate to thread screen */
}}
/>
This passes the generics through appropriately to custom components and other props, in this case the custom Message
component would receive the generics.
Hooks
Hooks, including those to access contexts, also require generics to be applied to correctly type custom returns.
useChannelContext
for instance would have the previous generics applied to it to get a correctly typed return for channel
.
const { channel } = useChannelContext<StreamChatGenerics>();