如何将这些类型谓词的类型分配给它们的参数类型? 简答长答案

问题描述

以下是我想要实现的:

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 方式吗? :-)


回复答案

非常感谢你们有见地的回答,伙计们。以下是我的回复

@Linda Paiste

不要费心创建一个 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 更冗长。

@Andrei Tătar

你能看看这个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

Playground Link

,

所以,最后我想出了以下几点:

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

Playground

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...