【问题标题】:Typescript automatic generic type without explicitly declare the typeTypescript 自动泛型类型,无需显式声明类型
【发布时间】:2021-06-19 03:51:45
【问题描述】:

如果我有一个具有两个功能的接口。一个函数返回一个值。我想在同一接口的另一个函数中使用值的类型。我确实使用了泛型,但每次创建新对象时都必须显式声明类型。但没有它也可以做到。例如:

interface myObject<T> {
    create(): T
    update(value: T): void // use value type defined in create method
}

这里我们使用上面的接口定义新对象:

let test: myObject<string> = {
    create() {
        return "Hello"
    },
    update(value) {
        // do something with value
    },
}

没有&lt;string&gt; 也可以写myObject。 create 方法中已经定义了值类型?

【问题讨论】:

  • 请注意,非原始类型名称通常以大写字符开头,如MyObject,而不是myObject。
  • 我已经删除了我的答案以支持@jcalz 的答案,我的答案有一些不必要的开销
  • @captain-yossarian 这是不相关的答案
  • 我想要的不是对象创建,而是我想在泛型中省略 &lt;type&gt; 并自动使用 create 方法中的类型。避免编写不必要的代码并使事情更干净。
  • @jcalz 可以实例化命名类或任何内容的约定。在我的例子中是的,我可以使用这个约定。但与其他对象。像任何其他变量一样命名它

标签: typescript typescript-generics


【解决方案1】:

初步命名约定注意事项:标准做法是以大写字符开头的非原始类型名称,以将它们与变量/属性名称或原始类型区分开来。因此,我将在此答案中使用 MyObject 而不是 myObject:

interface MyObject<T> {
    create(): T
    update(value: T): void
}

--

您希望编译器推断 string 用于泛型类型参数T。这种generic type parameter inference 发生的唯一地方是当您调用泛型函数时,因此如果您想要这种行为,您需要从类型注释(const test: MyObject&lt;string&gt; = ...)重构为调用辅助函数(const test = toMyObject(...))。

此外,您希望编译器推断update 方法的value 回调参数的类型。这种类型的推理称为contextual typing。

不幸的是,回调参数的上下文类型推断和泛型类型参数推断在两者都依赖于同一个对象时不能很好地配合使用。这是 TypeScript 的设计限制。请参阅microsoft/TypeScript#38872 了解更多信息。

为了同时获得上下文类型推断和泛型类型参数推断,您的辅助函数需要将输入对象分成两部分:一部分用于create,以便可以推断泛型类型参数T,另一个用于update,以便推断回调参数value的类型。

这给了我们这个:

const toMyObject = <T,>(
    create: () => T,
    update: (value: T) => void
): MyObject<T> => ({ create, update });

让我们测试一下:

let test = toMyObject(
    () => { return "Hello" },
    (value) => { console.log(value.toUpperCase()); }
);
// let test: MyObject<string>

看起来不错。编译器根据需要推断test 是MyObject&lt;string&gt; 类型,并且回调参数value 也推断为string(正如在--strict 模式下可以毫无错误地调用value.toUpperCase() 的事实所证明的那样)。


Playground link to code

【讨论】:

  • 谢谢。但它仍然在函数参数中重复代码。在我看来,它不如使用泛型参数本身那么干净。我在实际代码中有更多方法。所以我会避免这种情况
  • 您可能确实更喜欢自己指定泛型类型参数。但是“在函数参数中复制代码”只会在函数定义中发生一次,然后您可以根据需要多次使用它,而无需进一步重复。单个函数定义是否过多的开销取决于您正在创建的这些对象的数量。无论如何,目前没有其他方法可以让编译器同时推断通用T 和value 的类型,因此可能的答案是这个或者不幸的是“不,你不能这样做”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-30
  • 2015-12-14
  • 2018-12-14
  • 1970-01-01
  • 2019-04-02
相关资源
最近更新 更多