javascript - Koji je dobar način da se pronađe kojem uniji varijabla pripada?


Pokušavao sam kreirati funkciju gdje je parametar funkcije unija sastavljena od dvije druge unije. Želim da ovisno o stringu koji se proslijedi u parametar, odgovarajuća funkcija bude pozvana. Nešto poput ovoga:

type Type1 = "a" | "b" | "c";
type Type2 = "x" | "y" | "z";

function doSomething(param: Type1 | Type2) {
    // if param is a part of the "Type1" union
         functionForTypeOne();
}

doSomething("z");

Pretražovao sam internet i dokumentaciju i nisam mogao pronaći način kako napraviti provjeru tipa u runtime-u. Pronašao sam neka 'rješenja' za provjeru tipa, ali svi su bila napisana za tipove objekata, a ne za stringove i unije.

U osnovnom JavaScriptu mogao bih stvoriti const niz i provjeriti nalazi li se niz unutar niza, ovako:

const type1 = ["a", "b", "c"];
const type2 = ["x", "y", "z"];

function doSomething(param) {
    if (type1.includes(param))
        functionForTypeOne();
}

Raditi ovo u TypeScriptu je nekako rješenje, ali budući da trebam kreirati unije od ovih konstanti, to mi se čini vrlo neučinkovitim i ne dopušta mi da koristim značajke provjere tipova jezika. Zanimalo me ima li netko rješenje za ovo koje sam možda previdio, ili je ovo jedini način da zaobiđem svoj problem.

Odgovor #1

Unije iz svojih torki možete izgraditi gotovo automatski i koristiti predikat za provjeru tipa kako biste vratili sigurnost tipa:

const type1 = ["a", "b", "c"] as const; // Assert as const to infer tuple instead of array string[]
const type2 = ["x", "y", "z"] as const;

// Automatically get union type from tuple values
type Type1 = typeof type1[number];
//   ^? "a" | "b" | "c"
type Type2 = typeof type2[number];
//   ^? "x" | "y" | "z"

// Type guard predicate
function isIn<T extends readonly string[]>(val: string, arr: T): val is T[number] {
    return arr.includes(val);
}

function doSomething(param: Type1 | Type2) {
    param
    //^? "a" | "b" | "c" | "x" | "y" | "z"
    if (isIn(param, type1)) {
        param
        //^? "a" | "b" | "c"
        //functionForTypeOne();
    }
}

Veza za igralište