Question
I have the following TypeScript type:
type Event = {
name: string;
dateCreated: string;
type: string;
};
I want to create a new type based on it by adding another property, for example:
type UserEvent extends Event = {
userId: string;
};
This does not work. How can I correctly extend a type in TypeScript?
Short Answer
By the end of this page, you will understand how to build new types from existing ones in TypeScript. You will learn the correct way to extend object shapes using interface extends and type intersections with &, when to use each approach, and how this pattern appears in real codebases.
Concept
In TypeScript, type aliases and interface declarations are similar, but they are not extended in exactly the same way.
If you define an object shape with type, you cannot write type NewType extends OldType = .... That syntax is not valid TypeScript.
To create a new type from an existing type, the usual approach is to use an intersection type with &:
type Event = {
name: string;
dateCreated: string;
type: string;
};
type UserEvent = Event & {
userId: string;
};
This means: take everything from Event and combine it with userId.
Another option is to use interface, which does support extends directly:
Mental Model
Think of a TypeScript object type like a checklist of required fields.
Event says:
- must have
name - must have
dateCreated - must have
type
Now imagine you want a stricter checklist for a user-specific event. You do not throw away the original checklist. You stack another checklist on top of it.
So UserEvent means:
- everything required by
Event - plus
userId
Using & is like merging two checklists together.
Using interface extends is like saying: “Start with this checklist, then add one more rule.”
Syntax and Examples
Extending a type with &
type Event = {
name: string;
dateCreated: string;
type: string;
};
type UserEvent = Event & {
userId: string;
};
UserEvent now requires all four properties.
const loginEvent: UserEvent = {
name: "User Login",
dateCreated: "2026-05-04",
type: "auth",
userId: "u123"
};
Using interface extends
interface Event {
name: string;
dateCreated: string;
: ;
}
{
: ;
}
Step by Step Execution
Consider this example:
type Event = {
name: string;
dateCreated: string;
type: string;
};
type UserEvent = Event & {
userId: string;
};
const event: UserEvent = {
name: "Purchase",
dateCreated: "2026-05-04",
type: "order",
userId: "user-42"
};
Here is what happens step by step:
Eventis defined as an object type with 3 required string properties.UserEventis created by combining:- all properties from
Event - one extra property:
userId
- all properties from
- When TypeScript checks the
eventobject, it expects:name
Real World Use Cases
This pattern is very common in real applications.
API models
A base response type may contain common fields:
type BaseRecord = {
id: string;
createdAt: string;
};
type User = BaseRecord & {
email: string;
};
type Product = BaseRecord & {
price: number;
};
Event tracking
Analytics systems often have shared event fields plus event-specific fields.
type BaseEvent = {
timestamp: string;
eventType: string;
};
type ClickEvent = BaseEvent & {
elementId: string;
};
Backend validation models
You may define a base entity and extend it for different use cases such as create, update, or response types.
UI state objects
A component may reuse a base data shape and add local UI properties like loading state or error messages.
Real Codebase Usage
In real projects, developers usually combine small reusable types instead of repeating full object definitions.
Common patterns
Base domain models
type BaseEntity = {
id: string;
createdAt: string;
updatedAt: string;
};
type Post = BaseEntity & {
title: string;
body: string;
};
Error handling
type ApiError = {
message: string;
code: string;
};
type FieldError = ApiError & {
field: string;
};
Configuration objects
type BaseConfig = {
env: string;
};
type DbConfig = & {
: ;
};
Common Mistakes
1. Trying to use extends with type
This is the exact problem in the question.
// Incorrect
type UserEvent extends Event = {
userId: string;
};
Use this instead:
type UserEvent = Event & {
userId: string;
};
2. Confusing type and interface
This works:
interface Event {
name: string;
}
interface UserEvent extends Event {
userId: string;
}
But this does not:
= {
: ;
};
= {
: ;
};
Comparisons
| Approach | Syntax | Best for | Notes |
|---|---|---|---|
Extend with interface | interface UserEvent extends Event { ... } | Object shapes | Clean and readable for object inheritance |
Combine with type intersection | type UserEvent = Event & { ... } | Reusing type aliases | Works well with unions and utility types |
| Duplicate fields manually | Write all properties again | Almost never ideal | Repetition increases maintenance cost |
type vs interface
Cheat Sheet
// Base type
type Event = {
name: string;
dateCreated: string;
type: string;
};
// Correct: extend a type alias using &
type UserEvent = Event & {
userId: string;
};
// Alternative: use interfaces
interface Event {
name: string;
dateCreated: string;
type: string;
}
interface UserEvent extends Event {
userId: string;
}
Rules to remember
type X extends Y = ...is invalid.- Use
&to combinetypealiases. - Use
extendswithinterface.
FAQ
Can a TypeScript type extend another type?
Not with extends syntax in the alias declaration. Use an intersection with & instead.
How do I add properties to an existing type in TypeScript?
Create a new type using &:
type UserEvent = Event & { userId: string };
Should I use type or interface in TypeScript?
Use either consistently. interface is great for object shapes and extends; type is more flexible for unions, intersections, and other compositions.
Is interface extends the same as type &?
They are often similar for object shapes, but they are not identical in every advanced case. For this use case, both can model the same result.
Why does type UserEvent extends Event = ... fail?
Mini Project
Description
Build a small event model for an application that tracks different kinds of events. You will start with a shared base type and create more specific event types by extending it. This demonstrates how real TypeScript projects reuse type definitions instead of duplicating fields.
Goal
Create reusable event types where each specific event includes all base event fields plus its own additional properties.
Requirements
- Create a base event type with
name,dateCreated, andtype. - Create a
UserEventtype that addsuserId. - Create a
PurchaseEventtype that addsuserIdandamount. - Declare one valid object for each specific type.
- Write a function that accepts a
UserEventand logs its information.
Keep learning
Related questions
Angular formGroup Error Explained: Fixing 'Can't bind to formGroup' in Reactive Forms
Learn why Angular shows 'Can't bind to formGroup' and how to fix it by importing ReactiveFormsModule correctly.
Fix "Element implicitly has an 'any' type" in TypeScript Object Indexing
Learn why TypeScript rejects string object indexing and how to fix it with keyof, unions, and typed object keys in React.
Fix "Property has no initializer" in Angular TypeScript Components
Learn why Angular TypeScript shows "Property has no initializer" and how to fix it using defaults, optional properties, or definite assignment.