I have an array of given union type, then wants to check if a string from a superset of the union type is contained in the array (runtime check):
const validOptions: ("foo" | "bar")[] = ["foo", "bar"]
type IArrType = typeof validOptions[number]
const key: IArrType | "alien" = "alien" // Rather: some random function
const isKeyInArr = validOptions.indexOf(key) > -1 // Error: "alien" is not assignable to "foo" | "bar"
// Fix 1:
const isKeyValidCast = validOptions.indexOf(<IArrType>key) > -1
// Fix 2:
const isKeyValidExplicit =
key === "alien" ? false : validOptions.indexOf(key) > -1 // OK: type guard magic
Fix 1 is OK but not very elegant. Fix 2 fools the compiler but is misleading and inefficient runtime. In my case the "alien" string type is just a placeholder for any string not in the union type.
Is there any ways this can be compiled without casting or explicit tests? Can the expression be negated so that we get this "type guard" to work?
BTW: This very cool answer show how to construct a typed tuple from a list of values: Typescript derive union type from tuple/array values