dragonmnl dragonmnl - 1 year ago 159
TypeScript Question

in Typescript, what is the proper way to define type which is a subset of the actual value?

As per the title.

In my Ionic 2 (Angular2 / TS) app I'm using a cordova plugin (geolocation) which returns a set of fields which include latitude and longitude (but also other fields such as altitude: number etc.).

These are however the only 2 fields of my interest, so I defined the type:

coordinates: {latitude: number; longitude: number;};

Is this the correct way to define a type for a variable which would eventually have also other properties (e.g. latitude)?
If not, what is the right way?

Answer Source

Typescript checks the shape of types and can allow extra properties, so long as it can verify the required properties are present.

For example, you can define a type and function like:

type Coordinates = {latitude: number, longitude: number};

function logCoordinates(coords: Coordinates) {
  console.log('coordinates:', coords.latitude, coords.longitude);

and Typescript will happily accept any of these calls:

logCoordinates({latitude: 1, longitude: 2});

// assuming we have a CoordinateClass know to have lat and long
const coordinates = new CoordinateClass(1, 2); 

The type annotation describes the shape of a contract. Any parameter that we can prove meets that contract is allowed. However, extra properties are not always allowed.

If you have extra properties and are passing an object literal -- class instances don't have this problem -- you may need to cast them into the desired type:

logCoordinates(<Coordinates>{latitude: 1, longitude: 2, altitude: 3});

You can solve that more robustly using an intersection type, as described here, which removes the need to cast by accepting any unmatched key:

type Coordinates = {latitude: number, longitude: number} & {[key: string]: number};