微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法使用打字稿扩展/继承泛型

如何解决无法使用打字稿扩展/继承泛型

我在将泛型与打字稿中的接口扩展相结合时遇到了麻烦。我的基本用例是这样的:

  1. 基本界面
  2. 从父接口扩展的子接口(只有 1 级深度继承)
  3. 每个子接口都包含不在基接口中的数据
  4. 某些字段可能会或可能不会在各种同级接口之间共享

我希望能够编写一个类型安全的泛型函数,该函数可以正确识别一般的子接口,包括适当地将参数匹配到泛型接口。

我已经成功地将鉴别器用于扩展接口,但我无法将其与其他参数联系起来。例如:

这是我们的基本类型,以及鉴别器值“Type”:

interface Base<T> {
    type: T
    a: string
    b: number
}

以下是可能的扩展/继承者:

type ExtensionType = 'CDate' | 'DBool' | 'CString'

interface ExtensionCDate<T = 'CDate'> extends Base<T> {
    c: Date
}

interface ExtensionDBool<T = 'DBool'> extends Base<T> {
    d: boolean
}

interface ExtensionCString<T = 'CString'> extends Base<T> {
    c: string
}

这里的想法是 ExtensionCDate 只能采用 'CDate' 的泛型值,因此它的类型值始终是 'CDate' 等。

这是我尝试解决此问题的方法

  1. 使用可能的子接口的联合类型:
type GenericExtension<T extends ExtensionType> = ExtensionCDate | ExtensionDBool | ExtensionCString
  1. 为每个子接口生成一个对应的接口,该接口只包含子接口中存在但基接口中不存在的字段(本质上是设置差异):
type ExtendedData<T extends ExtensionType> = Omit<GenericExtension<T>,keyof Base<T>>
  1. 编写一个函数,使用歧视来正确处理每个可能的孩子:
const genericFunc = <T extends ExtensionType>(obj: GenericExtension<T>,data: ExtendedData<T>): void => {
    switch ( obj.type ) {
        case 'CDate':
            obj.c = data.c  // data.c should exist
            return
        case 'DBool':
            obj.d = data.d  // data.d should exist
            return 
        case 'CString':
            obj.c = data.c  // data.c should exist
            return
    }
}

不幸的是,虽然 obj 的输入似乎有效,但鉴别器也不适用于 data 参数。我知道我可以使用强制转换(data.c 作为 ExcludedData),但我发现它有一个不理想的解决方案。

我得到的错误如下:

TS2339: Property 'c' does not exist on type 'Pick,never>'.

这让我觉得我至少在错误地做 ExtendedData 类型。 我觉得解决方案应该相当简单。我在这里错过了什么?

谢谢!如果我可以提供任何其他上下文来帮助提出解决方案,请告诉我。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。