【发布时间】:2026-01-31 09:15:01
【问题描述】:
我有一个objectMap() 函数,它接受一个对象,将一个函数应用于每个值,并返回一个具有相同键但值不同的对象。我为它写了以下声明:
declare function objectMap<TInputObject, TOutputValue>(
target: TInputObject,
callback: (currentValue: TInputObject[keyof TInputObject]) => TOutputValue,
): {[k in keyof TInputObject]: TOutputValue};
我希望这会使用在对象值中找到的类型调用回调函数,并返回一个与输入对象具有相同键结构的对象。这适用于大多数类型的对象,例如简单的映射,甚至字符串文字的联合:
type in1 = {[k: string]: string}
type keys = 'a' | 'b' | 'c'
type in2 = {[k in keys]: number}
但它会被字符串文字联合类型的可选键分解:
type keys = 'a' | 'b' | 'c'
type in = {[key in keys]?: number }
在这种情况下,当我尝试使用该功能时:
const obj : {[key in keys]?: number} = {a: 1, b: 2}
const result = objectMap(obj, x => x+1)
变量x 的类型为number | undefined(即使所有存在的键都有一个实际的数值),而result 除了可选键之外,最终还有未定义的值。
如何更改objectMap() 的声明以便获得预期结果,其中x 只是number 而result 是{[k in keys]?: number?
【问题讨论】:
-
{a?: number}和{a?: number | undefined}类型是相同的,假设您启用了--strictNullChecks。在 TypeScript 中(从 TS3.5 开始)并不总是可以distinguish a missing property from one which is present with anundefinedvalue。 -
另外,请尝试将此代码编辑为 minimal reproducible example,以演示您所看到的问题。就目前而言,
objectMap({a: 1, b: 2}, x => x + 1)没有您描述的问题;x被推断为number,输出类型为{a: number; b: number}。 -
@jcalz 我打开了严格的空检查,这是导致问题的部分原因(尽管直到我刚刚关闭它才意识到这就是所涉及的)。如果我将其关闭,
x的类型将缩减为number,一切都很好。 -
@jcalz 感谢您发现这个例子的问题,我试图做一个最小的例子,但不小心把它压缩得太多了。已编辑。
-
我不建议关闭
--strictNullChecks;它通常解决的问题多于产生的问题。
标签: typescript union-types object-object-mapping