如何在不使用类型断言的情况下检查字符串是否包含在字符串文字类型中?

Jen*_*lly 4 typescript

我经常有这样的字符串文字类型:

const supportedLanguageTags = [
    "de-at",
    "de-ch",
    "de-de",
    "en-gb",
    "en-us",
] as const;

type LanguageTag = typeof supportedLanguageTags[number];

function isSupportedLanguageTag(tag: string): tag is LanguageTag {
    return (supportedLanguageTags as unknown as string[]).includes(tag);
}
Run Code Online (Sandbox Code Playgroud)

在这里,我使用数组来定义类型,但也能够检查文字类型中是否包含随机字符串。

但是我真的不喜欢类型断言。您有摆脱它的建议吗?

一种解决方案是使用对象而不是数组,如下所示:

const supportedLanguageTags = {
    "de-at": 1,
    "de-ch": 1,
    "de-de": 1,
    "en-gb": 1,
    "en-us": 1,
};

type LanguageTag = keyof typeof supportedLanguageTags;

function isSupportedLanguageTag(tag: string): tag is LanguageTag {
    return tag in supportedLanguageTags;
}
Run Code Online (Sandbox Code Playgroud)

但在这里我不喜欢为每个对象属性定义一个随机值。

jca*_*alz 8

正如在类似问题的答案中提到的,调用签名的 TypeScript 类型Array.prototype.includes()要求搜索的值与数组元素的类型相同。如果数组元素属于 类型string,那么您可以搜索任意string。但是,如果数组元素的类型比string,例如字符串文字类型的联合,那么您将无法搜索任意. 对于类型安全来说,这个限制并不是真正必要的;您应该能够安全地搜索比元素类型更广泛的内容。string

问题microsoft/TypeScript#26255已在此处打开以寻求支持,但它作为microsoft/TypeScript#14520的重复项被关闭,这是关于表示超类型约束的一种方式。TypeScript 只有extends, whereU extends T意味着它U必须是 的某个子类型T。因为Array<T>你确实想要类似的东西includes<U super T>(searchElement: U): boolean,其中U super T意味着它U必须是 的某种超类型T。但 TypeScript 没有这样的语法。您可以使用条件类型(例如 )来模拟它,includes<U extends (T extends U ? unknown : never)>(searchElement: U)但这相当复杂,并且目前不是 TypeScript 类型的一部分。


您在这里可以做的一件事是将数组的类型安全地扩展到readonly string[]. 数组类型是未知的超类型,具有诸如 之类的变异readonly方法。字符串文字数组可以安全地扩展为,因为您不会修改其内容,并且将任何字符串文字类型的值读入需要.stringpush()readonly string[]string

类型断言允许(安全)扩大和(不安全)缩小。但是,如果您想确保没有意外地进行不安全的缩小,您可以放弃类型断言,而是注释一个新变量。类型注释仅支持安全扩展。

这意味着你可以这样写:

function isSupportedLanguageTag(tag: string): tag is LanguageTag {
  const s: readonly string[] = supportedLanguageTags; // okay
  return s.includes(tag); // okay
}
Run Code Online (Sandbox Code Playgroud)

而且你有类型安全。同样,该s变量并不是真正必要的,return (supportedLanguageTage as readonly string[]).includes(tag);如果您重视简洁而不是安全保证,则类型断言会将其简化为更简洁。

Playground 代码链接