Table of contents

  1. 1. Assignment Compatibility
  2. 2. Optional and Additional Properties
  3. 3. Disallowing Properties
  4. 4. Preventing Compatibility

TypeScript uses a structural type system, which means that type compatibility is based on the shape or structure of the types rather than their explicit declarations or names. This allows you to define two types with different names but identical properties, enabling interchangeability between them.

Assignment Compatibility

One type can be assigned to another if they share at least the same properties. The assigned type must include all the required properties of the target type, with compatible types for each property.

In the example below, an instance of Dog can be passed to the logCatName function since both Cat and Dog types have the same properties:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type Cat = {
age: number;
name: string;
}

type Dog = {
age: number;
name: string;
}

function logCatName(animal: Cat) {
console.log(animal.name);
}

const bobby: Dog = {
age: 5,
name: 'Bobby'
};

logCatName(bobby);

Optional and Additional Properties

The compatibility remains intact even when optional properties (e.g., catTag) don’t conflict in terms of typing. Additional properties, such as dogTag, are compatible as long as the target type doesn’t explicitly prohibit them:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Cat = {
age: number;
name: string;
catTag?: number;
}

type Dog = {
age: number;
name: string;
dogTag: number;
}

function logCatName(animal: Cat) {
console.log(animal.name);
}

const bobby: Dog = {
age: 5,
name: 'Bobby',
dogTag: 1337
};

logCatName(bobby);

Disallowing Properties

To explicitly disallow a property, you can utilize the never type, which will require you to update your code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type Cat = {
age: number;
name: string;
catTag?: number;
dogTag: never;
}

type Dog = {
age: number;
name: string;
dogTag: number;
}

function logCatName(animal: Cat) {
console.log(animal.name);
}

const bobby: Dog = {
age: 5,
name: 'Bobby',
dogTag: 1337
};

// TS2345: Argument of type 'Dog' is not assignable to parameter of type 'Cat'.
logCatName(bobby);

Preventing Compatibility

Type compatibility applies not only to plain types but also to instances of classes. If you want to prevent type compatibility, you can use Discriminated Unions or the branded types programming pattern.