如何在Typescript中为嵌套对象中的键创建一个守卫?

huangapple go评论71阅读模式
英文:

How to create a guard in Typescript for keys in a nested object?

问题

以下是代码的中文翻译部分:

type PossibleKeys = 'a' | 'b' | 'c';

type MappedObject = {
  test: {
    [key in PossibleKeys]?: { foo: boolean };
  }
}
const mappedObject: MappedObject = {
  test: {
    a: { foo: true },
    b: { foo: false },
  }
}

function mappedObjectHasKeyDefined(possibleKey: PossibleKeys): possibleKey is keyof MappedObject['test'] {
  return possibleKey in mappedObject.test;
}

const c: PossibleKeys = 'c';
const array: PossibleKeys[] = ['a', 'b', 'c'];

array.forEach((newT: PossibleKeys) => {
  // 所有这些类型保护似乎都不起作用
  if(
    mappedObject.test[newT] !== undefined 
    && newT in mappedObject.test 
    && mappedObject.test
    && mappedObject.test[newT]
    && Object.prototype.hasOwnProperty.call(mappedObject.test, newT)
    && mappedObjectHasKeyDefined(newT)
  ) {
    // 对象可能为 'undefined'。
    const a = mappedObject.test[newT].foo;
  }
})

链接至 TypeScript Playground

英文:

I have a nested object that contains an object with multiple optional properties. I would like to create a typeguard to prevent the Object is possibly undefined. I do not know if this is possible or that I should cast it.

type PossibleKeys = 'a' | 'b' | 'c';

type MappedObject = {
  test: {
    [key in PossibleKeys]?: { foo: boolean };
  }
}
const mappedObject: MappedObject = {
  test: {
    a: { foo: true },
    b: { foo: false },
  }
}

function mappedObjectHasKeyDefined(possibleKey: PossibleKeys): possibleKey is keyof MappedObject['test'] {
  return possibleKey in mappedObject.test;
}

const c: PossibleKeys = 'c';
const array: PossibleKeys[] = ['a', 'b', 'c'];

array.forEach((newT: PossibleKeys) => {
  // all of these guards somehow do not seem to work
  if(
    mappedObject.test[newT] !== undefined 
    && newT in mappedObject.test 
    && mappedObject.test
    && mappedObject.test[newT]
    && Object.prototype.hasOwnProperty.call(mappedObject.test, newT)
    && mappedObjectHasKeyDefined(newT)
  ) {
    // Object is possibly 'undefined'.
    const a = mappedObject.test[newT].foo;
  }
})

Link to the typescript playground

答案1

得分: 0

TypeScript当前不会在obj[key]形式的属性访问的外观类型上进行缩小,当key不是单一字符串字面类型时。如果key只是string类型,或者如果它是字符串字面类型的联合类型(如PossibleKeys),或者如果它是泛型类型,编译器将不会缩小属性的类型。这仍然是一个待解决的功能请求,跟踪在microsoft/TypeScript#10530

目前的解决方法是将属性复制到一个新变量中,因为变量可以通过检查来缩小类型。以下是一种方法:

array.forEach((newT: PossibleKeys) => {
  const t = mappedObject.test; // 可行
  const u = t[newT]; // 可行
  if (u) {
    const a = u.foo // 可行
  }
})

代码的Playground链接

英文:

TypeScript doesn't currently narrow the apparent types of property accesses of the form obj[key] when key is not of a single string literal type. If key is just of type string, or if it's a union of string literal types (like PossibleKeys) or if it's a generic type, the compiler will not narrow the type of the property. This is still an open feature request, tracked at microsoft/TypeScript#10530.

Currently the workaround is to copy the property into a new variable, since variables can be narrowed via checks. Here's one way to do it:

array.forEach((newT: PossibleKeys) => {
const t = mappedObject.test; // okay
const u = t[newT]; // okay
if (u) {
const a = u.foo // okay
}
})

Playground link to code

huangapple
  • 本文由 发表于 2023年7月4日 23:25:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76614044.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定