【问题标题】:How to check if a given value is in a union type array如何检查给定值是否在联合类型数组中
【发布时间】:2018-10-09 15:53:47
【问题描述】:

我有一个给定联合类型的数组,然后想检查来自联合类型超集的字符串是否包含在数组中(运行时检查):

const validOptions: ("foo" | "bar")[] = ["foo", "bar"]
type IArrType = typeof validOptions[number]
const key: IArrType | "alien" = "alien" // Rather: some random function
const isKeyInArr = validOptions.indexOf(key) > -1 // Error: "alien" is not assignable to "foo" | "bar"

// Fix 1:
const isKeyValidCast = validOptions.indexOf(<IArrType>key) > -1 
// Fix 2:
const isKeyValidExplicit = 
      key === "alien" ? false : validOptions.indexOf(key) > -1 // OK: type guard magic

Fix 1 可以,但不是很优雅。 Fix 2 欺骗了编译器,但运行时具有误导性和低效。在我的情况下,“外星人”字符串类型只是任何不在联合类型中的字符串的占位符。

有没有什么方法可以在没有强制转换或显式测试的情况下编译?可以否定表达式,以便我们让这个“类型保护”工作吗?

顺便说一句:这个非常酷的答案展示了如何从值列表构造一个类型化的元组:Typescript derive union type from tuple/array values

【问题讨论】:

  • 可能(arr as string[]).indexOf(key) 是你最好的选择。
  • @jcalz - 是的,我同意投射 arrary 比投射参数更好。代码的意图更清楚。然而,最终使用了自定义保护函数和find()。

标签: typescript


【解决方案1】:

最大的问题是如何处理所有不是ConfigurationKeys 的可能值而不明确检查每个值。我将它们命名为 Configuration,因为这是非常常见的场景。

您可以将逻辑隐藏在您自己的保护函数后面,告诉编译器:我可以处理类型检查,相信我。它被value is ConfigurationKeys 返回类型识别。

代码示例 (live):

type ConfigurationKeys = "foo" | "bar";

function isConfiguration(value: string): value is ConfigurationKeys {
    const allowedKeys: string[] = ["foo", "bar"];
    
    return allowedKeys.indexOf(value) !== -1;
}

const key: string = "alien" // Rather: some random function

if (isConfiguration(key)) { 
    // key => ConfigurationKeys
} else { 
    // key => string
}

我发现编写自己的保护函数是使用联合类型的非常干净的解决方案。有时仍然需要类型转换,但在这里您将转换和逻辑隐藏在单个代码中。

参考:

【讨论】:

  • 我添加了一个自定义的守卫功能,它确实提高了一点代码质量。但是我仍然需要演员,因为我的allowedKeys 结构版本是一个类型化字符串的元组。因此indexOf 表达式没有它就无法编译。
  • 您也可以使用find,它具有不同的类型定义,允许与基本类型不同的值。见:allowedKeys.find(el =&gt; el === value) !== undefined
  • 使用find 和自定义守卫让我足够接近。这个结构很容易推理,没有任何强制转换。谢谢!
  • 输入配置键 | string 被编译器折叠为 string,因此您可以将 isConfiguration(value: ConfigurationKeys | string) 简化为 isConfiguration(value: string)
  • 类型守卫很棒,但这是当前编写的危险模式。如果ConfigurationKeys 发生变化而您忘记更新allowedKeys 以匹配,那么您将有一个类型保护器在编译时和运行时错误地验证字符串。输入检查 allowedKeys 和 ConfigurationKeys 是一个简单的更改。
【解决方案2】:

接受的答案使用类型断言/强制转换,但从 cmets 看来,OP 采用了使用 find 的解决方案,但工作方式不同。我也更喜欢那个解决方案,所以这是它的工作原理:

const configKeys = ['foo', 'bar'] as const;
type ConfigKey = typeof configKeys[number]; // "foo" | "bar"

// Return a typed ConfigKey from a string read at runtime (or throw if invalid).
function getTypedConfigKey(maybeConfigKey: string): ConfigKey {
    const configKey = configKeys.find((validKey) => validKey === maybeConfigKey);
    if (configKey) {
        return configKey;
    }
    throw new Error(`String "${maybeConfigKey}" is not a valid config key.`);
}

请注意,这可以保证字符串在运行时和编译时都是有效的ConfigKey。

【讨论】:

    猜你喜欢
    • 2022-07-08
    • 1970-01-01
    • 2023-01-24
    • 2020-02-24
    • 1970-01-01
    • 2015-08-14
    • 2021-10-26
    • 2016-07-24
    • 1970-01-01
    相关资源
    最近更新 更多