很抱歉,我是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有点陌生。预先感谢!
使metafunction
通用。
如上所述,没有通用类型。为了安全起见,firstClosure
仅会使用foo
和bar
共有的密钥,但是它们没有共同的密钥,因此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将类型信息分别保留为metafunction
和firstClosure
的属性,从而为闭包提供所需的类型。
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"
}
}
}