繁体   English   中英

通用类型未解析为联合

[英]Generic Type Not Resolving to Union

以下代码错误:


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 Child1 | Child2 有没有办法做到这一点?

可以做到,但它需要更多的泛型类型参数:

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 

提香的回答非常好。 为了完整起见,这是我的尝试:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM