简体   繁体   English

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

[英]Narrowing string to string literal union

I want to narrow a string to a string literal union.我想将字符串缩小为字符串文字联合。 In other words, I want to check if the string is one of the possible values of my literal union, so that this will work (if the operator couldbe existed).换句话说,我想检查字符串是否是我的文字联合的可能值之一,这样它就可以工作(如果运算couldbe可能存在)。

type lit = "A" | "B" | "C";
let uni: lit;
let str = "B";
if(str couldbe lit){
    uni = str;
} else {
    doSomething(str);
}

How can I achieve this?我怎样才能做到这一点?

I tried using if (str instanceof lit) , but that doesn't seem to work.我尝试使用if (str instanceof lit) ,但这似乎不起作用。 Using keyof to iterate over the string union doesn't work either, because the allowed values aren't keys per se.使用keyof遍历字符串联合也不起作用,因为允许的值本身不是键。

One way would be to use switch with one case for each possible value, but that could lead to subtle errors if lit s allowed values change.一种方法是对每个可能的值使用一个 case 的switch ,但是如果lit允许的值发生变化,这可能会导致细微的错误。

You can useUser-Defined Type Guards .您可以使用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);
}

ADD:添加:

To avoid duplicated edit, class can be used both for compile-time and run-time.为避免重复编辑, class可用于编译时和运行时。 Now all you have to do is to edit just one place.现在您只需编辑一处即可。

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;
}

If you hate switch cases, as I do:如果你讨厌 switch case,就像我一样:
since TypeScript 3.4 – const assertions it's also possible to produce union type from array of your strings ^_^由于TypeScript 3.4 – const 断言,也可以从字符串数组中生成联合类型 ^_^

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

This is my take on the problem with the type guard and with strictNullChecks turned off (this is limitation on a project; if this option is true TS will require exhaustiveness on the switch/case ).这是我对类型保护和关闭strictNullChecks问题的strictNullChecks (这是对项目的限制;如果此选项为true TS 将需要详尽无遗的switch/case )。

Line const _notLit: never = maybeLit;const _notLit: never = maybeLit; guaranties that when you change lit type you need to update the switch/case also.保证当您更改lit类型时,您还需要更新switch/case

Downside of this solution is that it gets very verbose as the union type lit grows.这个解决方案的缺点是,随着联合类型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;
}

If possible this task is more suitable for enum or if you require a type and don't mind creating underlying enum for checking, you can create type guard something like this:如果可能,此任务更适合enum或者如果您需要一个type并且不介意创建底层枚举进行检查,您可以创建类似这样的类型保护:

enum litEnum {
  "A",
  "B",
  "C",
}
type lit = keyof typeof litEnum;

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

You can also use a zod enum to do this:您还可以使用zod枚举来执行此操作:

import zod from 'zod'

const ColorMode = zod.enum(['light', 'dark', 'system'] as const)

let _mode = 'light' // type is string
let mode = ColorMode.parse(_mode) // type is "light" | "dark" | "system"

_mode = 'twilight'
mode = ColorMode.parse(_mode) // throws an error, not a valid value

You can also extract the type from the zod schema when needed:您还可以在需要时从 zod 模式中提取类型:

type ColorMode = zod.infer<typeof ColorMode>

I find a validation library like this is the easiest and most robust way to parse, validate, and type-narrow variables/data when I would otherwise have to reach for manually-written and error-prone type guards/predicates .我发现像这样的验证库是解析、验证和缩小变量/数据类型的最简单和最可靠的方法,否则我将不得不使用手动编写且容易出错的类型保护/谓词

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM