How to Correctly Extend Types in TypeScript

Is it Possible to Extend Types in TypeScript? Suppose you have the following type in TypeScript:

type Event = {
   name: string;
   dateCreated: string;
   type: string;
}

Now, you want to extend this type to create a new type like so:

type UserEvent extends Event = {
   UserId: string; 
}

However, this approach doesn’t work. How can you correctly extend a type in TypeScript?

The extends keyword can only be used with interfaces and classes in TypeScript. To declare a type that includes additional properties, you can use an intersection type:

type UserEvent = Event & { UserId: string };

As of TypeScript 2.2, you can also have an interface extend another type, provided the type meets certain restrictions:

type Event = {
   name: string;
   dateCreated: string;
   type: string;
}

interface UserEvent extends Event {
   UserId: string;
}

However, it does not work the other way around—UserEvent must be declared as an interface if you want to use the extends syntax. Additionally, extending arbitrary types is still not supported. For instance, you cannot use extends with a type parameter that lacks constraints.

Building on the idea of using intersection types to extend a type in TypeScript, you can intersect multiple types using the & operator. For example:

type TypeA = {
    nameA: string;
};

type TypeB = {
    nameB: string;
};

export type TypeC = TypeA & TypeB;

With this intersection, you can now create an object that satisfies both TypeA and TypeB:

const some: TypeC = {
    nameB: 'B',
    nameA: 'A',
};

This method ensures that the new type combines properties from both types. This is particularly useful when you need to create complex types that merge multiple interfaces or types.

Taking the concept of extending types in TypeScript further, you can create a generic extended type as follows:


type Extension<T> = T & { someExtensionProperty: string };

This approach allows you to extend any type T with an additional property, someExtensionProperty. For example:


type EventWithExtension = Extension<Event>;

Now, EventWithExtension will have all properties from Event plus someExtensionProperty. This method provides a flexible way to extend types dynamically and is particularly useful when working with generic types or building reusable components.