BloodyRain2k
BloodyRain2k

Reputation: 365

How do I enforce type checks for TypeScript interface properties?

I'm working on a TypeScript React project and it has among others interfaces like this defined. The problem is that this seems to do nothing more than tell me in VSCode, what the types of the object I'm pushing into the array should be. But when it's actually being executed it takes whatever and runs with that until something else breaks.

export interface IBooking {
  id: number;
  layoutName: string;
  gridItemId: number;
  gridItemName: string;
  userLoginId: number;
  layoutNameId: number;
  date: Date;
}

Here's the code that populates an array of IBooking objects to be handed off to the React portion of the app. The API queried for the result unfortunately formatted those ids as strings, despite being numbers. And TypeScript simply takes those string numbers, throws them into the properties and moves on, which down the line causes a bunch of === checks comparing against actual numbers to fail.

let vBookingItems: IBooking[] = [];
...
queryResult.forEach(element =>
  vBookingItems.push({
    id: element.id, // actually a string
    gridItemId: element.fields.vItemIdLookupId, // actually a string
    gridItemName: element.lookup.vItemIdLookupId.Title,
    layoutNameId: element.fields.vLayoutNameLookupId, // actually a string
    layoutName: element.lookup.vLayoutNameLookupId.Title,
    userLoginId: element.fields.vUserLookupId, // actually a string
    date: element.fields.vBookingDate,
  })
);

I'm aware that I'll have to change something about either the interface's types or the API's result to get the types to match eventually, but that's a bigger undertaking as I am not the one who started this project, I'm only expanding on it.

So my question right now is: what's the simplest way to make TypeScript pay attention to the types it gets and either at least attempts to parse strings into numbers for these 4 properties, without me having to manually run parseInt() on each, or at least complain that :any doesn't match the needed type, so this doesn't just silently breaks, as it's doing right now.

Do I need to convert the interface into a class and work with getters and setters or what's the best solution here?

Upvotes: 0

Views: 815

Answers (1)

Matija Sirk
Matija Sirk

Reputation: 960

Typescript runs at compile time, not at runtime. As such it cannot know what shape of data you will get at runtime from API (from outside Typescript code) and so has to trust you that you will type external data correctly.

It also cannot convert data automatically between types - you need to use explicit parseInt or depend on js frankly weird type coercion rules.

My usual approach is to provide as RecordTypeRaw to return of fetch() function, then clean it and depend on type inference from that point of.

Explicit is always better than implicit. Writting parseInt() four times is not so bad as spending few days debugging why language changed return of API to number.

Upvotes: 1

Related Questions