[英]Why is Typescript coercing my keyof type to a never type and how do I fix it?
Sorry if this is a dupe, I'm new to TypeScript and am having trouble figuring out if similar-looking questions are related because a lot of them are doing very complex things.对不起,如果这是一个骗局,我是 TypeScript 的新手,并且无法弄清楚看起来相似的问题是否相关,因为他们中的很多人都在做非常复杂的事情。 Anyway the problem is, I have a relatively simple setup that TS is choking on because it's coercing a type to
never
and I don't really understand why it's doing that.无论如何,问题是,我有一个相对简单的设置,TS 正在窒息,因为它强制一种类型
never
,我真的不明白它为什么这样做。 Here's the setup:这是设置:
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)
My expectation is that the value of value
will be "a".我的期望是 value 的
value
将是“a”。
I don't understand why littleObjProp
resolves to never
.我不明白为什么
littleObjProp
解析为never
。 My assumption would be that because LittleObject
is built from the type of the argument passed in to metafunction
, TS would pick which "sub interface" to use for any given invocation.我的假设是,由于
LittleObject
是从传递给参数的类型内置metafunction
,TS会选择使用任何给定调用其“子接口”。 So, for example, when I call metafunction("foo")
, TS would set LittleObject
to { a?: string; b?: string }
因此,例如,当我调用
metafunction("foo")
,TS 会将LittleObject
设置为{ a?: string; b?: string }
{ a?: string; b?: string }
and thus, when I call firstClosure("a")
, it would say, "ah yes, 'a' is indeed a valid key of LittleObject, carry on". { a?: string; b?: string }
因此,当我调用firstClosure("a")
,它会说,“啊,是的,'a' 确实是 LittleObject 的有效键,继续”。 It can't do this, however, because it always thinks that keyof LittleObject
means never
.然而,它不能这样做,因为它总是认为
keyof LittleObject
意味着never
。
Can someone help me understand 1) why it's doing this and 2) how to accomplish what I'm trying to do?有人可以帮助我理解 1) 为什么这样做和 2) 如何完成我正在尝试做的事情? I realize it's a weird setup but I'm dealing with some weird React libraries and this is just where I am at the moment.
我意识到这是一个奇怪的设置,但我正在处理一些奇怪的 React 库,而这正是我目前所处的位置。 Please assume I have to keep the same overall structure of a function returning a function returning a function as seen in the example.
请假设我必须保持一个函数的整体结构,该函数返回一个返回一个函数的函数,如示例中所示。 Also I would really appreciate it if you could keep your answer as simple as possible since I am a bit new to TS.
另外,如果您能尽可能简单地回答我的问题,我将不胜感激,因为我对 TS 有点陌生。 Thanks in advance!
提前致谢!
Make metafunction
generic.使
metafunction
通用。
As you have it above, there's no generic type.正如上面所说,没有泛型类型。 To be safe
firstClosure
is only going to take a key that foo
and bar
have in common, but they have no key in common so never
is the only possible parameter.为了安全起见,
firstClosure
只会采用foo
和bar
共有的键,但它们没有共同的键,所以never
是唯一可能的参数。 If you were to give them a key in common, firstClosure
would be typed to accept that.如果您要给它们一个共同的键,
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
By adding a generic, you can convince Typescript to keep the type information as a property of metafunction
and firstClosure
each, which gives your closure the type you're looking for.通过添加泛型,您可以说服 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"
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.