繁体   English   中英

为什么 Typescript 将我的 keyof 类型强制为 never 类型,我该如何解决?

[英]Why is Typescript coercing my keyof type to a never type and how do I fix it?

对不起,如果这是一个骗局,我是 TypeScript 的新手,并且无法弄清楚看起来相似的问题是否相关,因为他们中的很多人都在做非常复杂的事情。 无论如何,问题是,我有一个相对简单的设置,TS 正在窒息,因为它强制一种类型never ,我真的不明白它为什么这样做。 这是设置:

interface BigObject {
  foo: {
    a?: string
    b?: string
  }
  bar: {
    c?: string
    d?: string
  }
}

const instance: BigObject = {
  foo: {
    a: "a",
    b: "b",
  },
  bar: {
    c: "c",
    d: "d",
  }
}

function metafunction(bigObjProp: keyof BigObject) {
  type LittleObject = BigObject[typeof bigObjProp]
  // IDE hints show this ^^ as being correct, i.e. either of the two "sub interfaces"

  return function (littleObjProp: keyof LittleObject) { // <== littleObjProp is resolving to never
    return function (bigObject: BigObject) {
      const littleObject = bigObject[bigObjProp]
      return littleObject ? littleObject[littleObjProp] : "fallback value"
    }
  }
}

const firstClosure = metafunction("foo")
const secondClosure = firstClosure("a") // <== Argument of type "a" is not assignable to type "never"
const value = secondClosure(instance)

我的期望是 value 的value将是“a”。

我不明白为什么littleObjProp解析为never 我的假设是,由于LittleObject是从传递给参数的类型内置metafunction ,TS会选择使用任何给定调用其“子接口”。 因此,例如,当我调用metafunction("foo") ,TS 会将LittleObject设置为{ a?: string; b?: string } { a?: string; b?: string }因此,当我调用firstClosure("a") ,它会说,“啊,是的,'a' 确实是 LittleObject 的有效键,继续”。 然而,它不能这样做,因为它总是认为keyof LittleObject意味着never

有人可以帮助我理解 1) 为什么这样做和 2) 如何完成我正在尝试做的事情? 我意识到这是一个奇怪的设置,但我正在处理一些奇怪的 React 库,而这正是我目前所处的位置。 请假设我必须保持一个函数的整体结构,该函数返回一个返回一个函数的函数,如示例中所示。 另外,如果您能尽可能简单地回答我的问题,我将不胜感激,因为我对 TS 有点陌生。 提前致谢!

使metafunction通用。

正如上面所说,没有泛型类型。 为了安全起见, firstClosure只会采用foobar共有的键,但它们没有共同的键,所以never是唯一可能的参数。 如果您要给它们一个共同的键, firstClosure键入firstClosure以接受该键。

interface BigObject {
  foo: {
    a?: string
    b?: string
    f?: string   // Added
  }
  bar: {
    c?: string
    d?: string
    f?: string   // Added
  }
}

const instance: BigObject = {
  foo: {
    a: "a",
    b: "b",
    f: "f",
  },
  bar: {
    c: "c",
    d: "d",
    f: "f",
  }
}

const secondClosure = firstClosure("f")   // "f" is the only valid value

打字稿游乐场

通过添加泛型,您可以说服 Typescript 将类型信息保留为metafunctionfirstClosure每个的属性,这为您的闭包提供您正在寻找的类型。

function metafunction<T extends keyof BigObject>(bigObjProp: T) {
  type LittleObject = BigObject[T]

  return function (littleObjProp: keyof LittleObject) {
    return function (bigObject: BigObject) {
      const littleObject = bigObject[bigObjProp]
      return littleObject[littleObjProp] ?? "fallback value"
    }
  }
}

打字稿游乐场

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM