问题描述
以下是我想要实现的:
function isstring<T>( value: T ): value is T extends string ? T : string {
return typeof value === "string";
}
function isNotString<T>( value: T ): T extends string ? unkNown : T {
return typeof value !== "string";
}
但我收到一条错误消息,指出“类型谓词的类型必须可分配给其参数的类型。”这是预期的。
顺便说一句,我不想实现以下目标:
function isstring<T>( value: T ): Extract<T,string> {
return typeof value === "string";
}
function isNotString<T>( value: T ): Exclude<T,string> {
return typeof value !== "string";
}
因为,这两个都可能推断出我不想要的 never
类型。也就是说,我总是需要有一个已知类型来处理。
你能帮我实现这种 TypeScript 方式吗? :-)
回复答案
非常感谢你们有见地的回答,伙计们。以下是我的回复:
不要费心创建一个 isNotString 类型保护,因为它不会做你想要的。相反,检查 isstring 是否为 false,typescript 将正确推断所有内容。
你觉得下面的函数有什么问题吗?如果我没记错的话,我认为它达到了我的预期。
function isNotString<T>( value: T ): value is Exclude<T,string> {
return typeof value === "string";
}
我个人喜欢包含一个泛型并断言值是 T & 字符串,而不仅仅是值是字符串,这样如果类型已知是字符串的特定子集,则不会丢失任何信息。
我喜欢这种方法,但我以前以一种奇怪的方式实现了这一点。我不会在这里分享这个,因为这是一种疯狂的方法。
我们的 return 语句中没有任何 never ,但我们仍然在我们的代码中得到 never ,因为如果我们的 a: 字符串变量不是字符串,它是唯一的逻辑类型。
不能同意更多。我昨天肯定是疯了。 :-)
值得注意的是,typescript 的内置类型保护实际上并没有在否定情况下细化类型。这只是表明在处理像 T 这样的未知类型时,你无法真正正确地做到这一点。
我同意亲爱的。我只是想把它用于详细目的。也许我错了,但 isNotString
对我来说似乎比 ! isstring
更冗长。
你能看看这个Playground吗?
我可以看到 Exclude
按预期工作,但 value: T | string
没有。如果我遗漏了什么,请随时指出。
解决方法
你可以这样做:
function isNotString<T>(value: T | string): value is T {
return typeof value !== "string";
}
对于字符串检查,您可以简单地:
function isString(value: any): value is string {
return typeof value === "string";
}
,
简答
不要费心创建一个 isNotString
类型保护,因为它不会做你想要的。相反,请检查 isString
是否为 false,并且 typescript 将正确推断所有内容。
长答案
@Andrei 的回答是正确的,类型保护必须使用 value is
声明其返回。我想解决 never
的问题。类型保护是 true
/false
检查。其中一个分支检出,另一个不合逻辑,因此将是 never
。
假设这是我们的类型守卫。我个人喜欢包含一个泛型并断言 value is T & string
而不仅仅是 value is string
,这样如果类型已知是 string
的特定子集,则不会丢失任何信息。
function isString<T>( value: T ) : value is T & string {
return typeof value === "string";
}
现在我们想在 if
语句中使用这个类型保护。让我们看看当我们对一个类型已知的变量这样做时会发生什么。
const a: string = "something";
if (isString(a)) {
console.log(a); // `a` here is `string`
} else {
console.log(a); // `a` here is `never`
}
我们的 return 语句中没有任何 never
,但我们仍然在代码中得到 never
,因为如果我们的 a: string
变量不是 {{1 }}。
定义 string
类型保护并不是真正必要的,因为您也可以检查 isNotString
。但是如果我们想这样做,当用字符串调用时它会返回 ! isString()
。别的什么都没有意义。只有当函数为真时才应用断言。因此,如果 never
不是 string
,那么它是什么?
老实说,定义一个断言否定情况的类型保护真的很难,即。 string
,因为类型保护旨在断言肯定。 value is not string
似乎应该工作,但它不能区分联合,因为联合没有扩展 Exclude
,所以它总是返回 string
。我可以理解为什么这是您不想要的不良行为。所以不要这样做。您已经有一个守卫,可以查看某个东西是否是 never
,因此可以使用它来查看它是否不是string
,它会执行您想要的操作。
string
值得注意的是,typescript 的内置类型保护实际上并没有在否定情况下细化类型。这只是表明在处理 function checkUnion(value: string | number) {
if (!isString(value)) {
console.log(value); // `value` is `number`
}
if (isString(value)) {
console.log(value) // `value` is `string`
}
}
这样的未知类型时,您无法真正正确地做到这一点。
T
,
所以,最后我想出了以下几点:
function isString<T>( value: T ): value is T & string {
return typeof value === "string";
}
function isNotString<T>( value: T ): value is Exclude<T,string> {
return typeof value === "string";
}