将字符串缩小到字符串文字并集

Posted

技术标签:

【中文标题】将字符串缩小到字符串文字并集【英文标题】:Narrowing string to string literal union 【发布时间】:2017-10-15 17:21:27 【问题描述】:

我想将字符串缩小为字符串文字联合。换句话说,我想检查字符串是否是我的文字联合的可能值之一,以便这将起作用(如果运算符 couldbe 存在)。

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 对每个可能的值使用一种情况,但如果lits 允许的值发生变化,这可能会导致细微的错误。

【问题讨论】:

lit 类型在运行时不存在,因此您不能这样使用它。也许改用枚举? 关于switch语句注释,见answer。 @NitzanTomer 这实际上是一个非常好的主意,看起来更清晰,更容易理解。 【参考方案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;

【讨论】:

嗯,这比 switch 语句好一点,但它仍然存在当lits 允许的值更改时可能忘记更新类型保护的问题。 我为我的答案添加了另一个解决方案。 如果绝对必须使用文字联合,我非常喜欢您的第二种解决方案。不过,似乎更好的方法是切换到enums。【参考方案2】:

这是我对类型保护和关闭strictNullChecks 问题的看法(这是对项目的限制;如果此选项为true,TS 将要求对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 并且不介意创建底层枚举以进行检查,您可以创建类似这样的类型保护:

enum litEnum 
  "A",
  "B",
  "C",

type lit = keyof typeof litEnum;

function isLit(str: string): str is lit 
  return litEnum[str] !== undefined;

【讨论】:

【参考方案3】:

如果您像我一样讨厌开关盒: 因为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);

【讨论】:

以上是关于将字符串缩小到字符串文字并集的主要内容,如果未能解决你的问题,请参考以下文章

在EXCEL中怎么缩小字间距?在WORD中可以!

word怎样缩小字间距

通过解析 ELF C++ 程序,将字符串文字的地址映射到字符串文字

表格里怎么缩小字间距

为啥将文字 HTML 字符串附加到 DOM?

如何在自定义数字格式字符串中指定缩小 100?