以下代码错误:
class Base { }
class Child1 extends Base {
child1Fn() {}
static deserialize(bytes: Uint8Array): Child1 {
return new Child1();
}
}
class Child2 extends Base {
child2Fn() {}
static deserialize(bytes: Uint8Array): Child2 {
return new Child2();
}
}
const childMap = {
"child1": Child1.deserialize,
"child2": Child2.deserialize
}
function deserialize<T>(
data: { name: string, bytes: Uint8Array },
deserializeMap: Record<string, (bytes: Uint8Array) => T>
): T {
const deserializeFn = deserializeMap[data.name];
if (deserializeFn) {
return deserializeFn(data.bytes)
}
}
function deserializeChildMap(data: { name: string, bytes: Uint8Array }) {
return deserialize(data, childMap)
}
我最终遇到错误:
Argument of type '{ "child1": (bytes: Uint8Array) => Child1; "child2": (bytes: Uint8Array) => Child2; }' is not assignable to parameter of type 'Record<string, (bytes: Uint8Array) => Child1>'.
Property '"child2"' is incompatible with index signature.
Type '(bytes: Uint8Array) => Child2' is not assignable to type '(bytes: Uint8Array) => Child1'.
Property 'child1Fn' is missing in type 'Child2' but required in type 'Child1'.
它看起来将类型T
解析为childMap(Child1)中的第一个返回值。理想情况下,我希望T
解析为Child1 | Child2
。有没有办法做到这一点?
答案 0 :(得分:2)
可以做到,但是还需要一些通用类型参数:
class Base { }
class Child1 extends Base {
child1Fn() { }
static deserialize(bytes: Uint8Array): Child1 {
return new Child1();
}
}
class Child2 extends Base {
child2Fn() { }
static deserialize(bytes: Uint8Array): Child2 {
return new Child2();
}
}
const childMap = {
"child1": Child1.deserialize,
"child2": Child2.deserialize
}
function deserialize<TName extends string, TMap extends Record<TName, (bytes: Uint8Array) => any>>(
data: { name: TName, bytes: Uint8Array },
deserializeMap: TMap
): ReturnType<TMap[TName]> {
const deserializeFn = deserializeMap[data.name];
if (deserializeFn) {
return deserializeFn(data.bytes)
}
}
function deserializeChildMap<TName extends keyof typeof childMap>(data: { name: TName, bytes: Uint8Array }): ReturnType<typeof childMap[TName]> {
return deserialize(data, childMap)
}
let c1 = deserializeChildMap({ name: "child1", bytes: null!}) // child1
let c2 = deserializeChildMap({ name: "child2", bytes: null!}) // child2
答案 1 :(得分:0)
Titian's answer非常好。为了完整起见,这是我的目的:
function deserialize<T>(
data: { name: string, bytes: Uint8Array },
deserializeMap: { [key in keyof T]: (bytes: Uint8Array) => T[key] }
): T[keyof T] {
const deserializeFn = deserializeMap[data.name];
if (deserializeFn) {
return deserializeFn(data.bytes)
}
}
deserializeChildMap
的签名现在推断为:
function deserializeChildMap(data: { name: string; bytes: Uint8Array; }): Child1 | Child2