如何在 TypeScript 中通用地迭代任意对象的属性?



这是一个非常常见的JavaScript模式:

function mapThruWrapper(module) {
const replacement = {}
Object.getOwnPropertyNames(module).forEach(function(key) {
const val = module[key]
if (val instanceof Function) {
replacement[key] = wrapperFunc.bind(null, val)
} else {
replacement[key] = val
}
})
return replacement
}

我正在尝试在 TypeScript 中强键入它,我已经做到了如下所示:

function mapThruWrapper<M extends { [X: string]: unknown }>(module: M): M {
const replacement: M = {}
Object.getOwnPropertyNames(module).forEach(function(key) {
const val = module[key]
if (val instanceof Function) {
replacement[key] = wrapperFunc.bind(null, val)
} else {
replacement[key] = val
}
})
return replacement
}

不幸的是,这仍然会产生以下错误:

src/excmd.ts:186:10 - error TS2322: Type '{}' is not assignable to type 'M'.
'{}' is assignable to the constraint of type 'M', but 'M' could be instantiated with a different subtype of constraint '{ [X: string]: unknown; }'.
186    const replacement: M = {}
~~~~~~~~~~~
src/excmd.ts:192:10 - error TS2536: Type 'string' cannot be used to index type 'M'.
192          replacement[key] = buckleScriptErrorTrampoline.bind(null, $val)
~~~~~~~~~~~~~~~~

如何像这样强类型泛型迭代和包装对象的成员?

我对原始代码进行了一些调整,并添加了注释来解释:

function mapThruWrapper<M extends { [X: string]: unknown }>(module: M): M {
// Add "as M" so that the compiler allows us to assign an
// empty object (which is okay since we're populating all the
// object's properties before the function returns anyway).
const replacement: M = {} as M
// Use "for in" so that the compiler is able to infer
// that the variable "key" isn't just a string, but is
// actually a key in module's type.
for (const key in module) {
if (module.hasOwnProperty(key)) {
const val = module[key]
if (val instanceof Function) {
// Use "as typeof val" to let the compiler know that the
// bound function has the same signature as the original
// function. I'm assuming that's the case here.
replacement[key] = wrapperFunc.bind(null, val) as typeof val
} else {
replacement[key] = module[key]
}
}
}
return replacement
}

最新更新