我经常有这样的字符串文字类型:
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)
但在这里我不喜欢为每个对象属性定义一个随机值。
正如在类似问题的答案中提到的,调用签名的 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);如果您重视简洁而不是安全保证,则类型断言会将其简化为更简洁。
| 归档时间: |
|
| 查看次数: |
2498 次 |
| 最近记录: |