So we get some data from an API:

interface ResultsFromTheApi {
  usefulInfo: string;
  moreUsefulInfo: number;
  thingsWeCareAbout: boolean;
  factAboutCats: string;
  weatherReport: WeatherReport;
  diagnosticInformation: Diagnostics;
  addressOfOurHeadOffice: string;
  dateTheApiWasCompiled: string;
}

We use some of the fields, but since the type is provided by the API creator, it contains all the fields (even the ones we don’t care about like weatherReport).

const result: ResultsFromTheApi = fancyApi.getAllTheThings();
doSomething(result.usefulInfo, result.moreUsefulInfo, result.thingsWeCareAbout);

This is a little annoying, because in our test we create a full ResultsFromTheApi object even though most of the fields are irrelevant.

It gets more annoying in the future, when we want to update the API to a new version that has some changes – but they are all changes that don’t affect us.

 interface ResultsFromTheApi {
   usefulInfo: string;
   moreUsefulInfo: number;
   thingsWeCareAbout: boolean;
-  factAboutCats: string;
+  factAboutDogs: string;
   weatherReport: WeatherReport;
-  diagnosticInformation: Diagnostics;
+  diagnosticInfo: Diagnostics;
-  addressOfOurHeadOffice: string;
+  addressOfOurHeadOffice: string[];

When we pull in the new version, we get some compiler errors because our test data doesn’t match the ResultsFromTheApi interface anymore. We don’t use factAboutCats, diagnosticInformation, or addressOfOurHeadOffice, so we don’t care if the interface changed. It’s just noise.

We can fix the compiler errors by updating our test data to match the new API, but it’s a waste of time because the code doesn’t use any of the changed fields. The change makes no impact on our code, yet we have to make some updates so it will compile.

We could also get around this with using any type, but if we’re using any, what’s the point of using TypeScript instead of regular JavaScript? We want our compiler to check our code, but we don’t want it to complain about irrelevant changes.

Narrowing Our Types

What if we could tell the compiler that except for the three fields we need, we don’t care what the rest of that object contains?

In TypeScript, there are all kinds of nifty utility classes for transforming types.

Use Pick to take a subset of properties

The ResultsFromTheApi interface is provided for us by the API vendor and which includes many superfluous fields. Instead of using it directly in our code, we can narrow the type to only the part we want.

type ApiResultsWeNeed = Pick<ResultsFromTheApi, 'usefulInfo' | 'moreUsefulInfo' | 'thingsWeCareAbout'>;
const result: ApiResultsWeNeed = fancyApi.getAllTheThings();
doSomething(result.usefulInfo, result.moreUsefulInfo, result.thingsWeCareAbout);

The type ApiResultsWeNeed is a subset of ResultsFromTheApi that contains only the three fields that are relevant to our work. That means that when ResultsFromTheApi changes, it only impacts our code if the parts we use change.

More TypeScript utility types

Pick is one of many utility types provided by TypeScript. You may find it helpful to skim read the list, so the next time you want to modify a type, you have some ideas of what utility types to reach for.