657

Say I have the following type:

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

I now want to extend this type, i.e.

type UserEvent extends Event = {
   UserId: string; 
}

This doesn't work. How can I do this?

Kousha
  • 32,871
  • 51
  • 172
  • 296
  • 9
    The `type` keyword is used to define [type aliases](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-4.html#type-aliases), not interfaces or classes. – Heretic Monkey Dec 29 '16 at 18:20

5 Answers5

1221

The keyword extends can be used for interfaces and classes only.

If you just want to declare a type that has additional properties, you can use intersection type:

type UserEvent = Event & {UserId: string}

UPDATE for TypeScript 2.2, it's now possible to have an interface that extends object-like type, if the type satisfies some restrictions:

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

interface UserEvent extends Event {
   UserId: string; 
}

It does not work the other way round - UserEvent must be declared as interface, not a type if you want to use extends syntax.

And it's still impossible to use extend with arbitrary types - for example, it does not work if Event is a type parameter without any constraints.

AndreM96
  • 1,355
  • 1
  • 23
  • 34
artem
  • 46,476
  • 8
  • 74
  • 78
  • I am using TS v3.5.2, and I am not able to have an interface extend a type. `interface A extends B {blar}` An interface can only extend an object type or intersection of object types with statically known members – WORMSS Jul 18 '19 at 09:59
  • @WORMSS doing this `interface Identifiable extends T { id: string }` gives me error "An interface can only extend an object type or intersection of object types with statically known members.ts(2312)" – maninak Jun 15 '20 at 11:46
  • 1
    As typeScript is structurally typed, vs nominally, extending an 'arbitrary type' that has no further structure (constraints) will likely always be impossible. – Adam Tolley Aug 23 '21 at 15:24
  • @artem can we assign a value to some members while extending? for example: `interface UserEvent extends Event { name: 'test name'; UserId: string; }` – nikhil kekan Dec 13 '22 at 06:06
  • no the meaning of that is not what it seems - both `'test name'` and `string` here are types, not values - `'test name'` is a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types). You can't assign values in the interfaces, you can assign values in classes but within the class, the syntax for assignment is `name = 'test name'`, and `name: 'test name'` within the class is again declaring a type, not assigning a value. – artem Dec 13 '22 at 06:25
  • You could also in some cases want to use `|` when there isn't any overlap in the types but rather you want to have one more restrictive type and another that allows more types – OZZIE Apr 19 '23 at 05:28
125

you can intersect types:

type TypeA = {
    nameA: string;
};
type TypeB = {
    nameB: string;
};
export type TypeC = TypeA & TypeB;

somewhere in you code you can now do:

const some: TypeC = {
    nameB: 'B',
    nameA: 'A',
};
Community
  • 1
  • 1
Stan
  • 1,800
  • 1
  • 13
  • 15
  • 1
    This is a great solution. I'm working in React Native and this allows me to easily extend `TextInputProps` for my own custom text entry component. Thanks! – Nick Tiberi Sep 28 '20 at 14:01
  • 1
    I'm a little confused by this, surely this TypeC a union? I would expect an intersect of TypeA and TypeB would be {}? I.e. nothing in common? – Ben Taliadoros Oct 03 '22 at 15:53
  • @BenTaliadoros yes, its a bit confusing. [See this question & answers](https://stackoverflow.com/questions/38855908/naming-of-typescripts-union-and-intersection-types) – Juan Perez Oct 12 '22 at 15:15
31

A generic extension type can be written as follows:

type Extension<T> = T & { someExtensionProperty: string }
aegatlin
  • 1,711
  • 1
  • 13
  • 7
  • 2
    I would do something like this instead to make it truly generic: `type Extension = T & E;` – imp Nov 28 '22 at 19:47
28

What you are trying to achieve is equivalent to

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

interface UserEvent extends Event {
   UserId: string; 
}

The way you defined the types does not allow for specifying inheritance, however you can achieve something similar using intersection types, as artem pointed out.

Community
  • 1
  • 1
olydis
  • 3,192
  • 13
  • 28
1

If you have a type defined with Union (more than one possible types) and you want to add an additional type, you can do something like this

interface TextInputProps = { type: string };
interface TextAreaProps  = { type: string | number };

export type InputCompProps = TextInputProps | TextAreaProps

to

interface CustomProps = { length: number };
export type InputCompProps = (TextInputProps | TextAreaProps) & CustomProps
Mr.7
  • 2,292
  • 1
  • 20
  • 33