为什么Typescript将我的keyof类型强制转换为Never类型,以及如何解决?

问题描述 投票:1回答:1

很抱歉,我是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的值为“ a”。

我不明白为什么littleObjProp解析为never。我的假设是,因为LittleObject是根据传递给metafunction的参数的类型构建的,所以TS会选择对任何给定调用使用哪个“子接口”。因此,例如,当我调用metafunction("foo")时,TS会将LittleObject设置为{ a?: string; b?: string },因此,当我调用firstClosure("a")时,它会说:“是的,'a'确实是LittleObject的有效键, 继续”。但是,它无法执行此操作,因为它始终认为keyof LittleObject表示never

[有人可以帮助我了解1)为什么这样做和2)如何完成我想做的事情吗?我意识到这是一个怪异的设置,但是我正在处理一些怪异的React库,而这正是我目前所处的位置。请假设我必须保持返回函数的整体结构相同,如示例所示。同样,如果您能使回答尽可能简单,我将不胜感激,因为我对TS有点陌生。预先感谢!

typescript coercion
1个回答
2
投票

使metafunction通用。

如上所述,没有通用类型。为了安全起见,firstClosure仅会使用foobar共有的密钥,但是它们没有共同的密钥,因此never是唯一可能的参数。如果您要给他们一个共同的钥匙,则将输入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 playground

通过添加泛型,您可以说服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"
    }
  }
}

typescript playground

© www.soinside.com 2019 - 2024. All rights reserved.