"Object is possibly undefined" 当那不可能时

"Object is possibly undefined" when that is not possible

我正在定义一个 CDK 构造,它接收 props 对象并将其传递给 PythonFunction 的环境。由于环境参数需要非空字符串值(并且一些道具可以为空或非字符串类型),我有以下内容:

export interface MyConstructProps {
   key1: string,
   key2: string,
   key3?: string
   key4?: SomeOtherType
   [key: string]: string | SomeOtherType | undefined
 }

export class MyConstruct extends cdk.Construct {
  constructor(scope: Construct, id: string, props: MyConstructProps) {
    ...

    // within PythonFunction definition
    environment: Object.fromEntries(
      Object.entries(props)
        .filter(([k, v]) => v !== undefined)
        .map(([k, v]) => [k, v.toString()])
    ),
    ...
}

但是,这会产生错误 - v.toString() 中的 v 带有红色下划线,并带有消息 TS2532: Object is possibly 'undefined'..

我发现颠倒 mapfilter 的顺序可以编译并按预期工作:

Object.entries(props)
  .map(([k, v]) => {
    if (v === undefined) {
      return [k, v]
    } else {
      return [k, v.toString()]
    }
  })
  .filter(([k, v]) => v !== undefined)

如何以 TypeScript 识别类型限制的方式过滤掉数组中的值?

这与顺序关系不大,而与您使用的 narrowing if 语句允许 TS 正确推断这一事实有关。 IE,它也将按此顺序工作。

Object.entries(props)
  .filter(([k, v]) => v !== undefined)
  .map(([k, v]) => {
    if (v === undefined) {
      return [k, v]
    } else {
      return [k, v.toString()]
    }
  })

Filter 假定其 return 值始终与其谓词匹配相同的形状,这只是对其类型的简单限制。 TS 无法很好地评估 scope-boundaries 中的 compile-code。由于各种原因,IIRC 也没有尝试这样做,在许多情况下,模块可能会被扩充(从而改变实现),或者如果您愿意,您可以自己扩充(and/or 重载)声明。 https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation, OR to declare a different type only syntax here,即。 declare global {...},使用您自己的类型泛型来描述 return 值。

但没有太多意义,因为它与下面的答案一样冗长

你可以使用 as

(Object.entries(props)
    .filter(([k, v]) => v !== undefined) as [string, string][])
    .map(([k, v]) => [k, v.toString()])

TS Playground

上查看此内容

更简单的方法是使用断言:

      Object.entries(props)
        .filter(([k, v]) => v !== undefined)
        .map(([k, v]) => [k, v!.toString()])

! 用作 non-nullish 断言:

let nullable: string | undefined = "hello world";

nullable!.slice(0, 5); // "hello", no error