I am trying to filter based on a type in Typescript.
Essentially, I have 4 states, but on one screen I only want to display 3 of the options.
export const ADOPTION_LABELS: Record<
Collections.AdoptionReasons,
string
> = {
[AdoptionReasons.CuteDog]:
'It was a cute dog',
[AdoptionReasons.Behavior]:
'Behaved well',
[AdoptionReasons.ManuallyCreated]: 'Manually created',
[AdoptionReasons.Other]: 'Other',
};
On the screen, I show radio buttons where the user can select any reason. However, I want to filter out ManuallyCreated.
{Object.entries(ADOPTION_LABELS).map(([reason, label]) => (
<FormControlLabel
key={reason}
classes={{
label: classes.radioButtonLabel,
}}
control={<Radio value={reason} />}
label={label}
/>
))}
To do this, I created a new type:
export type SupportedAdoptionReasons = Exclude<
Collections.AdoptionReasons,
Collections.AdoptionReasons.ManuallyCreated
>;
I've been looking up type predicates, so have been trying to do something like
const isSupportedAdoptionReason = (label: string): label is SupportedAdoptionReasons => typeof label === instanceof SupportedAdoptionReasons)
and
const supportedAdoptionReasonLabels = Object.entries(ADOPTION_LABELS).filter(isSupportedAdoptionReason)
I feel like I'm getting really stuck when it comes to the type predicate. Can someone illuminate the best way forward?
Your type predicate is correct, but your isSupportedAdoptionReason function is wrong. instanceof returns a boolean and typeof label is always string, so the function will always return false. You also can't use a type as the instanceof operator, types are removed on build time and are not valid JavaScript objects.
Try this:
enum Test {
ONE = "one",
TWO = "two"
}
// Type predicate isn't even needed, but good to have if you want
const filterTest = (x: string, label: Test): x is Test => x !== label;
const testObj = {
[Test.ONE]: "hello",
[Test.TWO]: "world"
}
// returns [[[Test.ONE], "hello"]]
const filtered = Object.entries(testObj).filter(x => filterTest(x[0], Test.TWO))