Typing transformations in TypeScript
<p dir="auto">I really enjoy using TypeScript and use it in all of my own projects. There's just something about knowing what types your objects and functions are, and the great code completion in VSCode, that I always miss when working on a JavaScript project.
<p dir="auto">One big annoyance for me is when I have a certain type of an object and I want to create a copy of that type where some fields have a different type.<br />
I run into this a lot when receiving a type from a third-party library or an API request and I want to process and transform this object to make it easier to work with. As an example, consider an API endpoint that returns this type:
<pre><code>type ApiReponse = {
foo: number;
bar: string;
veryBigNumber: string; // overflows JS Number type, so it's encoded as a string by the API endpoint
date: string; // as ISOString "2020-05-30T11:39:40.230Z"
}
<p dir="auto">In my code I want to work with a JavaScript <code>Date object instead of an ISOString, so in my API fetch function I do this transformation:
<pre><code>type TransformedApiReponse = ?
const request = async ():Promise<TransformedApiReponse[]> => {
const result = await fetch<ApiReponse[]>(url)
return result.map(response => ({
...response,
veryBigNumber: new BigNumber(response.veryBigNumber),
date: new Date(response.date),
}))
}
<p dir="auto">While TypeScript allows you to easily extend an object type using the <code>& { newKey: string; } construct, it's hard to change an existing type.<br />
Or so I thougt.<br />
I used to copy and paste the existing ApiRepsonse type and then change the <code>date field. However, if the type comes from a third-party library that's not possible and there's an easier much better way using <a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link"><code>omit, one of TypeScript's utility types:
<pre><code>// before
type TransformedApiReponse = {
foo: number;
bar: string;
veryBigNumber: BigNumber; // changed
date: Date; // changed
}
// now
type TransformedApiReponse = Omit<ApiReponse, "date" | "veryBigNumber"> & {
veryBigNumber: BigNumber;
date: Date;
}
type New = Omit<ApiReponse,"date" | "veryBigNumber">
& {
veryBigNumber: BigNumber;
date: Date;
}
<p dir="auto">First, we use <code>Omit to remove the <code>date and <code>veryBigNumber field from the <code>ApiReponse type and then we extend the resulting type using the new type values.
<p dir="auto">This way, we only specify the change set for the type instead of the whole type, and if the API endpoint's response type changes we only need to update the original <code>ApiReponse type.
<p dir="auto">Have a look at some of the other <a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">TypeScript utility types - they can be very useful.<br />
These are the ones I use most often:
<pre><code>Omit, Pick, Partial, ReturnType
<hr />
<p dir="auto">Originally published at <a href="https://cmichel.io/typing-transformations-in-type-script/" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://cmichel.io/typing-transformations-in-type-script/