# Define TS Types for your Laravel Echo Events

Hey guys,

I've been working on a Laravel project (personal) for fun, focusing on the latest cool stuff: Laravel 11 & Reverb (from Broadcasting) ⭐️.

Using Laravel Broadcasting means you should use the client library provided by Laravel - Laravel Echo, to save a lot of your time setting up stuff 😎.

Even though Laravel Echo has been written in TypeScript, however, it doesn't give us any opportunity or battery to "type" our events 💣.

So that's why we have this topic and I'll show you how to define the types for your events 😉.

## Before going deeper

I suppose you already have some knowledge about:

* TypeScript
    
* Websocket & how it works
    
* [Laravel Broadcasting](https://laravel.com/docs/11.x/broadcasting)
    

🥹🥹🥹

## The Define Types for Laravel Echo

Note: I'm demonstrating on the [PresenceChannel](https://laravel.com/docs/11.x/broadcasting#presence-channels) (private channel with auth & more features).

### Extending the "PresenceChannel"

I'll create a file called `echo.ts` and extend the `PresenceChannel` interface

```typescript
type BaseEvent = {
  type: string;
  payload: unknown;
};

export interface StrictPresenceChannel<Event extends BaseEvent>
  extends PresenceChannel {
  listen<EventType extends Event['type']>(
    event: EventType,
    callback: (data: Extract<Event, { type: EventType }>['payload']) => void
  ): this;
}
```

This would be our base interface wrapper for the `PresenceChannel`.

In the real-life app, we would have *multiple channels* for communicating between client & server.

Each channel should **extend** the **base interface** and have its own Events declaration.

### Defining Events

Following the `BaseEvent` structure, we need to define all of the Events that would be sent to the client.

For a sample chat app, I've added these events:

```typescript
type ChatMessageAddedEvent = {
    type: 'ChatMessageAdded';
    payload: {
        fromUser: {
            id: string; // ULID
        },
        chat: {
            id: string;
            message: string;
        }
    }
}

type ChatImageAddedEvent = {
    type: 'ChatImageAdded';
    payload: {
        fromUser: {
            id: string; // ULID
        },
        chat: {
            id: string;
            imageUrl: string;
        }
    }
}

type ChatEvent = ChatMessageAddedEvent | ChatImageAddedEvent;
```

Don't forget to add a final type - a union of all events 😉, we'll use it in the part below.

### Create a Channel and Extend the StrictPresenceChannel

I created a `ChatChannel` interface and added the `ChatEvent` union type.

```typescript
export interface ChatChannel extends StrictPresenceChannel<ChatEvent> {}
```

### A function to join the Typed-Channel

```typescript
// getEchoInstance() is simply returning the new Echo({...})

export const getChatChannel = (channelId: string):  => {
  return getEchoInstance().join(channelId) as ChatChannel;
};
```

Here we have to hack a bit - using `as` to force the type.

This is the shortcut for a *quick win* & *hassle-free* while it won't result in any error or failure.

### Use the Typed-Channel instance 😎

```typescript
const channel = getRoomChannel(myChatChannel.id);

channel.listen('ChatMessageAdded', (data) => {
    // access data. & IDE will suggest the fields for you 
}).listen('ChatImageAdded', (data) => {
    // access data. & IDE will suggest the fields for you 
});
```

Then you're all set 😎 IDEs now will handle auto-suggestion, `eslint`/`tsc` can do the type check stuff in build time 💪

An example from my project:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711781689197/23324267-4210-4473-992b-5bd4c11f9ad5.png align="center")

### Notes

Note: this is purely defining types, it won't guarantee that your data is 100% valid and it could go wrong from the end user 🙀.

I'll make another topic for **schemas definition & data validation** for Laravel Echo soon, ensuring the data is legit to use ⭐️.

Stay tuned 🚀

## Conclusion

Well, that's basically it for defining types for your Broadcast Events 😎.

Have fun guys!
