typescript - Kontrollera om en sträng är medlem av Union-typ


För att undvika typomvandling skulle jag vilja lära mig när det är möjligt att säkert bestämma typen av givna värden. Jag kan göra detta med strängenummer som detta:

enum Category {
    circle = "circle",
    square = "square",
}

const isObjValue = (val: any, obj: any) => Object.values(obj).includes(val)

isObjValue('circle', Category) // true

Men hur skulle jag göra det med strängunioner?

const Category = "circle" | "square"

const isValidCategory = (string) => {
  if (/* string is in Category */) {
    return string as Category
  }
}

Lär mig fortfarande TS!

Svar #1

Om du har ett dynamiskt värde kan du skapa en användardefinierad typvakt för att begränsa typen av det värdet.

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")
}

Svar #2

För att slippa komma ihåg att alltid uppdatera både typen och "is"-kontrollfunktionen, kan du istället använda en array och låta TS konvertera den till en 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 )
}