将字符串缩小为字符串文字联合

时间:2017-05-16 14:43:48

标签: string typescript types literals unions

我想将字符串缩小为字符串文字联合。换句话说,我想检查字符串是否是我的文字联合的可能值之一,这样就可以了(如果操作符type lit = "A" | "B" | "C"; let uni: lit; let str = "B"; if(str couldbe lit){ uni = str; } else { doSomething(str); } 存在)。

if (str instanceof lit)

我如何实现这一目标?

我尝试使用keyof,但这似乎不起作用。使用switch迭代字符串联合也不起作用,因为允许的值本身不是键。

一种方法是使用lit为每个可能的值使用一个案例,但如果# -*- coding: utf-8 -*- 允许的值发生更改,则可能会导致细微的错误。

3 个答案:

答案 0 :(得分:1)

您可以使用User-Defined Type Guards

type lit = "A" | "B" | "C";
let uni: lit;
let str = "B";

function isLit(str: string): str is lit {
    return str == "A" || str == "B" || str == "C";
}
function doSomething(str: string) {

}

if (isLit(str)) {
    uni = str;
}
else {
    doSomething(str);
}

添加

为避免重复编辑,class可用于编译时和运行时。现在你所要做的就是只编辑一个地方。

class Lit {
    constructor(public A = 0, public B = 0, public C = 0) {}
}
type lit = keyof Lit;
let uni: lit;

function isLit(str: string): str is lit {
    let lit = new Lit();
    return (str in lit) ? true : false;
}

答案 1 :(得分:1)

这是我对类型保护和strictNullChecks关闭的问题的处理(这是对项目的限制;如果此选项为true,TS将需要对{{1} }。

switch/case行保证更改const _notLit: never = maybeLit;类型时还需要更新lit

该解决方案的缺点是,随着联合类型switch/case的增长,它变得非常冗长。

lit

如果可能,此任务更适合type lit = "A" | "B" | "C"; function isLit(str: string): str is lit { const maybeLit = str as lit; switch (maybeLit) { case "A": case "B": case "C": return true; } // assure exhaustiveness of the switch/case const _notLit: never = maybeLit; return false; } ,或者如果您需要enum并且不介意创建基础枚举进行检查,则可以创建如下类型的类型防护:

type

答案 2 :(得分:1)

如果你和我一样讨厌 switch case:
由于 TypeScript 3.4 – const assertions 也可以从字符串数组中生成联合类型 ^_^

const list = <const>["A", "B", "C"];
type Lit = typeof list[number]; // "A" | "B" | "C"

function isLit(str: string): str is Lit {
  return !!lits.find((lit) => str === lit);
}