# Difference between extending and intersecting interfaces in TypeScript?

Have you ever found yourself thinking in a complex project asking this question, then in this article I will try to answer with examples

Let's say the following type is defined:

```typescript
interface Shape {
  color: string;
}
```

Now, maybe we need a way to abstract further some properties but still keep them reusable as type, like in the following ways to add additional properties to this type:

We could go for an

**Extension**

```typescript
interface Square extends Shape {
  sideLength: number;
}
```

Or with using a type alias and thus an intersection

**Intersection**

```typescript
type Square = Shape & {
  sideLength: number;
}
```

Then what is the difference between both approaches?

Which one is better to use when or they basically in practice do not make any difference?

Let's start saying that there are differences which may or may not be relevant in a particular scenario.

Perhaps the most significant is the difference in how members with the same property key are handled when present in both types.

Consider:

```typescript
interface NumberToStringConverter {
  convert: (value: number) => string;
}

interface BidirectionalStringNumberConverter extends NumberToStringConverter {
  convert: (value: string) => number;
}
```

The `extends` above results in an error because the deriving interface declares a property with the same key as one in the derived interface but with an incompatible signature.

```typescript
error TS2430: Interface 'BidirectionalStringNumberConverter' incorrectly extends interface 'NumberToStringConverter'.

  Types of property 'convert' are incompatible.
      Type '(value: string) => number' is not assignable to type '(value: number) => string'.
          Types of parameters 'value' and 'value' are incompatible.
              Type 'number' is not assignable to type 'string'.
```

However, if we employ intersection types

```typescript
type NumberToStringConverter = {
  convert: (value: number) => string;
}

type BidirectionalStringNumberConverter = NumberToStringConverter & {
  convert: (value: string) => number;
}
```

There is no error whatsoever and, furthermore, this is useful indeed as a value conforming to this particular intersection type is easily conceived of.

```typescript
const converter: BidirectionalStringNumberConverter = {
    convert: (value: string | number) => {
        return (
          typeof value === 'string'
            ? Number(value)
            : String(value)
          ) as string & number; // type assertion is an unfortunately necessary hack.
    }
}
```

Note that the implementation of the intersection, as shown above, involves some awkward types and assertions but these are purely implementation artifacts which do not contribute to the type of the converter object which is solely determined by the type `BidirectionalStringNumberConverter` used to annotate the object literal `converter`.

let's see this applied:

```typescript
const s: string = converter.convert(0); // `convert`'s call signature comes from `NumberToStringConverter`

const n: number = converter.convert('a'); // `convert`'s call signature comes from `BidirectionalStringNumberConverter`
```

[Playground](https://www.typescriptlang.org/play/?ts=3.3.3#code/C4TwDgpgBAcgrgWwEYQE4BUD2BlYqCWAdgOYDCmhAbmsGlALxQDeAUFO1AMYXWrABcUABSUAhgBs4EQYUQpUASgYA+KAGc8RYgG4WAXxYtQkKACF8AE3yoInYPgoTcBEvGRpyVGnUYAyWHJoWM5anry0qFD+rBxcPDSCIhJSghouxEr0qrLuqLp6uiwA9EVQAIKEFlDAABb4alD1UKJQxJiYVbVajZUQEFWiDS1iktDchABmmKgI3cCY1TXQxtBNEIP44iBxhJwQ+NQWLOMaO+FoguZWNnYOhE6aroGoYd6RjDEc4+GJIynqj2IUAAPlAcvJMqpPrF2DZgHBUIRhCtMBMoH9oPQsVAAORpLQ4qAAfgCuSSoyUghCJHJUgUSkGAPSUTBz20UBK1XA0EGahod0aQyRcEm03h91oWzBtggajUolQ2xqok4AGsAHRsDgGAwnYDqVKAhhnN7q740IQABgU7M5AANzXw7XiuBJxOp8MQJQixpgELKoBNUH6oHa3PJgoDXnw0HbDHqwTJnsbHREzfE+EIcaIcTaOaUHRngM6Gpw3R6vaJ4TY4v6GkGQ3artZbPZHOJqcRwx4i7GgA)

Another important difference, `interface` declarations are open ended. New members can be added anywhere because multiple `interface` declarations with same name in the same declaration space are *merged*. This is in direct contrast to type expression produced by `&` which creates an anonymous expression that can be bound to an alias for reuse but not augmented via merging.

Here is a common use for merging behavior

**lib.d.ts**

```typescript
interface Array<T> {
  // map, filter, etc.
}
```

**array-flat-map-polyfill.ts**

```typescript
interface Array<T> {
  flatMap<R>(f: (x: T) => R[]): R[];
}

if (typeof Array.prototype.flatMap !== 'function') {
  Array.prototype.flatMap = function (f) { 
    // Implementation simplified for exposition. 
    return this.map(f).reduce((xs, ys) => [...xs, ...ys], []);
  }
}
```

Notice how no `extends` clause is present, although specified in separate files the interfaces are both in the global scope and are merged by name into a single logical interface declaration that has both sets of members. (the same can be done for module scoped declarations with slightly different syntax)

By contrast, intersection types, as stored in a `type` declaration, are closed, not subject to merging.

There are many, many differences. You can read more about both constructs in the TypeScript Handbook. The [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html#1) and the [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) sections are particularly relevant.
