Override Part of an Existing Type in Typescript
Bionic Julia
Posted on October 2, 2021
I've recently been on a mission to eliminate all Typescript errors in our code base at work, and have been steadily chipping away at them systematically, during any downtime I get. I used to dislike Typescript when I first came across it, but really love it now and get an immense sense of satisfaction watching the red squigglies disappear as I work through each Typescript issue, bit by bit. 🤓
It was whilst doing this last week that I came across a situation that was new to me. What I was faced with was this...
I have a component that takes in a prop item
which has an interface IItem
defined as:
interface IItem extends PickerItemProps {
iconSource?: ImageSourcePropType;
}
// ...and separately in another file, the React Native library provides this interface
export interface PickerItemProps {
testID?: string;
color?: ColorValue;
label: string;
value?: any;
}
If you're not familiar with Typescript, extends
effectively merges the PickerItemProps
interface into IItem
so that item
can take this form, for example:
const item: IItem = { iconSource: 'imagesourcelocation', label: 'An item' }
// How it's used
;<ParentComponent item={item} />
This issue I was faced with involved needing to extend the type label
. Instead of it always being a plain string, I needed to allow label
to also take the form of a component (the specific reason behind this has to do with how we're formatting certain bits of text in our app). Ideally then, label
needs to either be of type string
OR JSX.Element
.
Because label
actually belongs to and is defined in an external package, I didn't want to just change PickerItemProps
directly (since these might unknowingly be overwritten on upgrades etc.). I therefore naively tried to do this, but quickly ran into Typescript complaining loudly.
interface IItem extends PickerItemProps {
iconSource?: ImageSourcePropType;
label: string | JSX.Element; // Typescript complains that label already exists
}
// No changes to this
export interface PickerItemProps {
testID?: string;
color?: ColorValue;
label: string;
value?: any;
}
So what to do? The answer lies in using one of Typescript's utility types Omit
. From the Typescript documentation, Omit<Type, Keys>
...
Constructs a type by picking all properties from Type and then removing Keys (string literal or union of string literals).
What I could do in my case therefore, was to extends PickerItemProps
without label
, before then defining label as part of IItem
like so:
interface IItem extends Omit<PickerItemProps, 'label'> {
iconSource?: ImageSourcePropType;
label: string | JSX.Element;
}
// Original definition remains untouched
export interface PickerItemProps {
testID?: string;
color?: ColorValue;
label: string;
value?: any;
}
Questions or comments? Find my at my website, Twitter or Instagram.
Posted on October 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 22, 2023