Reputation: 735
To avoid type casting, I would like to learn when it's possible to safely determine the type of given values. I can do this with string enums like this:
enum Category {
circle = "circle",
square = "square",
}
const isObjValue = (val: any, obj: any) => Object.values(obj).includes(val)
isObjValue('circle', Category) // true
But how would I do it with string Unions?
const Category = "circle" | "square"
const isValidCategory = (string) => {
if (/* string is in Category */) {
return string as Category
}
}
Still learning TS!
Upvotes: 2
Views: 2588
Reputation: 2695
To avoid having to remember to always update both the type and "is" check function, you can instead use an array and have TS convert it to a union:
const ALL_CATEGORIES = ["circle", "square"] as const;
type typedCategoryList = typeof ALL_CATEGORIES;
type Category = typedCategoryList[number]; // this compiles to 'circle' | 'square'
const isCategory = (value: string) : value is Category => {
return ALL_CATEGORIES.includes(value as Category )
}
Upvotes: 3
Reputation: 2058
If you have a dynamic value, you can create a user-defined type guard, to narrow the type of that value.
type Category = "circle" | "square"
// User-defined type guard that narrows the s from string type
// to Category type if s is either "circle" or "square".
function isCategory(s: string): s is Category {
return s === "circle" || s === "square"
}
const a: string = "some dynamic string"
if (isCategory(a)) {
// a type here is Category
console.log(a, "is Category")
} else {
// a type here is string
console.log(a, "is not Category")
}
Upvotes: 4