39

I have problem with defined types and checking if a value is contained in that type.

Here is my example:

these are the types:

export type Key = 'features' | 'special';

export type TabTypes = 'info' | 'features' | 'special' | 'stars';

when the user changes a tab, it sends a string value from Type of TabTypes.

activeTabChanged(event: TabTypes) {
    this.activeTab: TabTypes = event;
    // it won't let me set the key here because key has a different type 
    // but the send event can be contained in type Key
    // how can I check if the send event from type TabTypes is contained in type Key
    this.key: Key = event;
}

is there a typescript way to check if a sent value with a type can equal a value from a different type?

Max
  • 739
  • 2
  • 8
  • 23
sanyooh
  • 1,260
  • 2
  • 18
  • 31

5 Answers5

26

2019 Solution:

I had the same need and found an easier way to do that in another thread. In summary, what Patrick Roberts says in that link (updated with this question values) is:

Don't over-complicate it.

function isOfTypeTabs (keyInput: string): keyInput is TabTypes {
  return ['info', 'features', 'special', 'stars'].includes(keyInput);
}

See What does the `is` keyword do in typescript? for more information on why we don't just use a boolean return type.

Credits and full source here: https://stackoverflow.com/a/57065680/6080254

Bruno Monteiro
  • 4,153
  • 5
  • 29
  • 48
5

You could use a string enum.

export enum Keys = {
  Features = 'features',
  Special = 'special',
}

// Compare it
if (currentKey === Keys.Special) { console.log('Special key is set'); }

In order to check if your value is defined in the predefined Enum at all you can do:

if (currentKey in Keys) { console.log('valid key'); }
kentor
  • 16,553
  • 20
  • 86
  • 144
  • 1
    `currentKey in Keys` Won't work with string enums, only with numeric enums – Maor Refaeli Jan 02 '20 at 15:08
  • 2
    As @MaorRefaeli says above the use of `currentKey in Keys` doesn't work at all. How this has upvotes at all is strange, because if you attempt this it won't work. I spent a good 15 minutes refactoring my code only for it to not work when I ran my code. – KG23 Sep 02 '22 at 21:31
2

This answer to a similar question might be useful. it doesn't exactly answer your question, but it shows a similar way to achieve the desired result.

In short, you can use array for inclusion checks, and type for type safety:

const keys = <const> ['features','special'];
export type Key = typeof keys[number];
const tabTypes = <const> ['info' ,'features' ,'special', 'stars'];
export type TabTypes = typeof tabTypes[number];

activeTabChanged(event: TabTypes) {
    this.activeTab: TabTypes = event;
    // it won't let me set the key here because key has a different type 
    // but the send event can be contained in type Key
    // how can I check if the send event from type TabTypes is contained in type Key

    if (event in keys) {
        this.key: Key = event as Key;
    }
}
Daniel Dror
  • 2,304
  • 28
  • 30
0
const TabValues = ['info', 'features', 'special', 'stars'] as const;
const TabValuesObj = TabValues.reduce(
  (acc, next) => ({ ...acc, [next]: null }),
  {} as Record<string, null>,
);
export type TabType = typeof TabValues[number];
export function isTabType(value: string): value is TabType {
  return value in TabValuesObj;
}

Here is an option that should also allow for very quick validation, even with large numbers of options in the type.

AntonOfTheWoods
  • 809
  • 13
  • 17
-1

While Array.includes works, it has linear time complexity. Assuming that your list of tab types is unique (using a union type with repeated values wouldn't really make sense), it's faster to use a Set

const tabsSet = new Set(['info', 'features', 'special', 'stars'])
const isOfTypeTabs = (keyInput: string): boolean => tabsSet.has(keyInput)

console.log(isOfTypeTabs('info')) // true
console.log(isOfTypeTabs('foo')) /
jpthesolver2
  • 1,107
  • 1
  • 12
  • 22
  • 1
    This is classical example of premature optimization. Array is actually faster, unless you have large number of elements in the array. This is because cache locality out weights linear time complexity. – Marko Feb 24 '23 at 18:41