TypeScript未发现变量中已执行未定义\null值检查

TypeScript未发现变量中已执行未定义\null值检查,typescript,Typescript,在下面的示例中,TypeScript没有看到参数.a和参数.b已检查是否存在未定义的值,并且在transformValue(parameters.a)行中无法定义: 类型示例={ a:字符串, b:字符串 } 功能示例(参数:{ a:字符串, b:字符串, skipA?:布尔值, skipB?:布尔值 }):例如{ const shouldReturnA=typeof parameters.a!=“未定义”&¶meters.skipA!==false; const shouldRetur

在下面的示例中,TypeScript没有看到
参数.a
参数.b
已检查是否存在未定义的值,并且在
transformValue(parameters.a)
中无法定义:

类型示例={
a:字符串,
b:字符串
}
功能示例(参数:{
a:字符串,
b:字符串,
skipA?:布尔值,
skipB?:布尔值
}):例如{
const shouldReturnA=typeof parameters.a!=“未定义”&¶meters.skipA!==false;
const shouldReturnB=typeof parameters.b!=“未定义”&¶meters.skipB!==false;
返回{
…应该返回a{a:transformValue(parameters.a)}:{},
…应该返回b?{b:transformValue(parameters.b)}:{}
}
}
函数transformValue(targetValue:string):string{
返回targetValue+“~~~”;
}
基于,有一种称为非空断言运算符

一个新的
修复后表达式运算符可用于在类型检查器无法得出结论的上下文中断言其操作数为非null和非未定义。具体来说,操作x!生成x类型的值,并排除null和undefined。与形式为
x
x as T
的类型断言类似,
非空断言运算符在发出的JavaScript代码中被简单删除

这里有一篇关于非空断言运算符的有用文章:

为什么它不能识别已完成的未定义检查? 导致TS编译器无法实现已检查的
a
b
的根本问题与“类型保护”的工作方式有关。您的代码
参数中有一个类型保护。a!==未定义(
skipX
上的检查与类型检查无关,因此将其排除在示例之外)。如果你这样使用它:

if (parameters.a !== undefined) {
  transformValue(parameters.a)
}
TS对此非常满意,因为
transformValue
调用在if语句中。这就是类型保护的工作方式,TS使用它们来“缩小”if块中变量的类型。在您的情况下,TS的设置并不是为了理解您之前在设置
shouldReturnA
的值时缩小了类型范围——人类可以看到它的逻辑,但对于TS来说,这是一段古老的历史,当它到达您的
时,它已经忘记了……shouldReturnA代码

替代方法 这并不像@dongnhan建议使用
那么快在变量之后,但您可能会喜欢它。我认为它把逻辑组织得更好一些,让它更枯燥一些,但这是我的观点

type Example = {
    a?: string,
    b?: string
}

function example(parameters: {
    a?: string,
    b?: string,
    skipA?: boolean,
    skipB?: boolean
}): Example {

    const validatedProp = (prop: string | undefined, shouldSkip: boolean | undefined) => 
      !shouldSkip && typeof prop === "string" ? { a: transformValue(prop) } : {}

    return {
        ...validatedProp(parameters.a, parameters.skipA),
        ...validatedProp(parameters.b, parameters.skipB),
    }
}

function transformValue(targetValue: string): string {
    return targetValue + "~~~";
}
通过进一步重构,仍有进一步改进的余地

关于
typeof
undefined
vs
'undefined'

请听埃斯林特的这首歌。
typeof
关键字将返回字符串“undefined”,而不是值
undefined
。除非您使用字符串,否则您的类型保护将不起作用(尽管注意,我比较了与“字符串”的正匹配)

为什么它不好<因为未定义可以被覆盖或隐藏
。老实说,您永远不会希望在代码中这样做(显然,重新分配或隐藏
未定义的
变量是一种不好的做法)。因此,您可以安全地关闭或忽略此规则(忽略单行或整个文件,eslint支持此忽略语法),请允许我再问一个问题。当ESLint文档被告知对
数据===undefined
“不做您认为它做的事情”时,它意味着什么?在上面一行,未定义的
被隐藏起来:
var undefined=“hi”
。这导致
data===undefined
被解释为
data===“hi”
(这是不可能的)。typescript并不完美,似乎它本身无法解决这种情况。您可以使用bang运算符来表示“嘿,ts,在这一行上它肯定不是null”
transformValue(parameters!.a)
感谢@Andrei指出,该运算符称为非空断言运算符。实际上,在本例中,您将放置
结尾如下:
transformValue(parameters.a!)
。通过一些研究,我更新了答案,并附上了一篇有用的文章。
if (parameters.a !== undefined) {
  transformValue(parameters.a)
}
type Example = {
    a?: string,
    b?: string
}

function example(parameters: {
    a?: string,
    b?: string,
    skipA?: boolean,
    skipB?: boolean
}): Example {

    const validatedProp = (prop: string | undefined, shouldSkip: boolean | undefined) => 
      !shouldSkip && typeof prop === "string" ? { a: transformValue(prop) } : {}

    return {
        ...validatedProp(parameters.a, parameters.skipA),
        ...validatedProp(parameters.b, parameters.skipB),
    }
}

function transformValue(targetValue: string): string {
    return targetValue + "~~~";
}