无比打字与拼英打字_打字稿中的多态性

无比打字与拼英打字

It’s not uncommon for people to think of Object-Oriented Programming and Functional Programming as mutually exclusive, and understandably so; any discussion involving the two turns quite often into a debate where rivalry is the central theme. But as it turns out, in some contexts, we can benefit from employing disciplines from both paradigms to get the best of two worlds. Ad-hoc Polymorphism in Typescript is one such context.

人们想到面向对象的编程并不少见 和函数式编程 可以理解为互斥的; 任何涉及这两个方面的讨论都经常变成以竞争为中心的辩论。 但是事实证明,在某些情况下,我们可以从两种范式中采用学科来受益,以充分利用两个世界。 打字稿中的临时多态性 就是这样一种背景。

场景 (The scenario)

Consider the case where we’re developing an inline-styling library. The library has different types that correspond to different CSS data types, such as:

考虑一下我们正在开发内联样式库的情况。 该库具有对应于不同CSS数据类型的不同类型,例如:

  • RGB

    RGB
  • RGBA

    RGBA
  • HSL

    高速钢
  • HSLA

    HSLA
  • HEX

    十六进制
  • Length

    长度
  • Percentage

    百分比
  • Decibel

    分贝
  • Time

    时间
  • Transformation

    转型

For the sake of simplicity, our interface for these inline-style objects will only support one property: The color property.

为了简单起见,我们用于这些内联样式对象的接口将仅支持一种属性: color属性。

Image for post

As demonstrated in the photo above, the value of the color property in our interface has a tagged-union type, which consists of a stringLiteral type and five other custom types represented as Javascript objects and modeled after the nominal-typing model described in my previous article.

如上图所示,我们界面中的color属性值具有一个标记联合类型,该类型由stringLiteral类型和其他五个自定义类型(表示为Javascript对象)组成,并按照我之前描述的标称类型模型进行建模文章

Now, within the boundaries of the library’s code, these types are well understood, and their values can be manipulated accordingly, but outside these boundaries — say in React, for example — they bare no meaning. For React to utilize these values for styling, we need to serialize them into either string or number values.

现在,在库代码的边界内,这些类型已得到很好的理解,并且它们的值可以进行相应的操作,但是在这些边界之外(例如在React中),它们毫无意义。 为了使React利用这些值进行样式设置,我们需要将它们序列化为stringnumber值。

问题 (The problem)

Based on our scenario, we need a function that serializes a color value into a string value. One way to do it can be this:

根据我们的方案,我们需要一个将颜色值序列化为string值的函数。 一种方法是:

Image for post

Nothing fancy here. We create small functions, each responsible for serializing a single subtype (a subtype of color) and then creating a function that checks the type of the passed argument (using type guards) and calls the function associated with that type. This approach results in excess code and an increased number of imports(in this case, we uses five imports).

这里没什么好看的。 我们创建了一些小的函数,每个函数负责序列化一个子类型(颜色的子类型),然后创建一个函数来检查传递的参数的类型(使用类型保护)并调用与该类型关联的函数。 这种方法导致代码过多和导入数量增加(在这种情况下,我们使用五个导入)。

In Haskell, you’d be using ad-hoc polymorphism to deal with this scenario. You’d have different implementations under the same name associated with different types, and Haskell will automatically pick the appropriate implementation for you depending on the type of the argument. If Typescript had it, it would “kinda” look something like this (without the error, of course):

在Haskell中,您将使用即席多态处理这种情况。 您将使用与不同类型关联的相同名称使用不同的实现,Haskell会根据参数的类型自动为您选择合适的实现。 如果Typescript拥有它,它将“有点”看起来像这样(当然没有错误):

Image for post

As you can see, TS’s compiler is complaining about “duplicate function implementation”. This error shows up because you can have multiple signatures under the same name, but only one implementation is allowed. This implementation is responsible for finding the appropriate function to call. So to fix the error, we need to do the following:

如您所见,TS的编译器抱怨“功能重复”。 出现此错误的原因是,您可以在同一名称下使用多个签名,但只允许一个实现。 此实现负责查找要调用的适当函数。 因此,要纠正该错误,我们需要执行以下操作:

Image for post

Absolutely worthless! We’ve ended up in a similar situation as before, only worse, with more code. Typescript calls this function overloading. It can be handy in many cases, but not in this one.

绝对一文不值! 我们最终陷入了与以前类似的情况,但更糟糕的是,有了更多的代码。 Typescript将此函数称为重载。 在许多情况下,它可能很方便,但在这种情况下却不是。

In Typescript, you can have many signatures under the same name, but only one implementation is allowed to associate with that name

在Typescript中,同一名称下可以有多个签名,但是只允许一个实现与该名称关联

Function overloading in TS didn’t work as expected, you feel sad and betrayed, the voice inside your head is urging you to reach out to the dark side, where all the poor objects scream in pain caused by mutations and method binding. But then, just right before you make your first step into the OOP world, I — your guardian angel — show up and stop you, offering you a middle ground, a safe place where your functions can thrive together with your objects in a pure atmosphere.

TS中的功能超载未能按预期工作,您感到难过和被出卖,您内心的声音敦促您伸向黑暗的一面,那里所有可怜的物体都因突变和方法绑定而痛苦地尖叫。 但是然后,就在您踏入OOP世界的第一步之前,我-您的守护天使-出现并阻止了您,为您提供了一个中间立场,一个安全的地方,您的功能可以在纯净的氛围中与您的对象一起蓬勃发展。

A glimpse into the OOP world
A glimpse into the OOP world
瞥见OOP世界

解决方案(The solution)

My go-to approach to this problem is to keep a reference of the function inside the “typed” object, stolen right from the OOP world. Don’t panic, there is no state involved in this approach, and the function is still referentially transparent. This reference is merely there to give easy and quick access to the appropriate function and eliminate code redundancy. We can do that by adding a property whose value is a reference of the function, something like this:

我要解决的这个问题的方法是将函数的引用保留在OOP世界中被盗的“类型化”对象内。 不要惊慌,也没有参与这种做法状态,而且功能还指称transparen。 该参考仅用于使您轻松快速地访问适当的功能并消除代码冗余。 我们可以通过添加一个属性值来实现此目的,该属性的值是函数的引用,如下所示:

Image for post

You can ignore the properties type and data. Thergb function is just a factory function that creates values of type RGB. The resulting object will have the property serialize that points to the function serializeRGB. Following this pattern with our other custom types, we can now refactor our serializeColor function to the following form:

您可以忽略属性typedatargb函数只是一个工厂函数,它创建RGB类型的值。 得到的对象将有物业serialize指向功能serializeRGB 。 遵循此模式以及其他自定义类型,我们现在可以将serializeColor函数重构为以下形式:

Image for post

Each type is responsible for pointing to its own implementation of the serialization behavior, no need for imports, or manual type checking.

每种类型都有责任指向自己的序列化行为实现,无需导入,也无需手动进行类型检查。

I hope you agree with me that this is way neater than the previous version. If you don’t, that’s fine. We all have the right to have our own opinions, just leave a comment, and I’ll let Liam Neeson find you and convince you of mine.

我希望您同意我的看法,这比以前的版本更加整洁。 如果您不这样做,那很好。 我们所有人都有发表意见的权利,请发表评论,我会让利亚姆·尼森(Liam Neeson)找到您并说服您。

We can keep references to functions inside objects to associate a particular type with an overloaded behavior without breaking the purity of our functional code.

我们可以保留对对象内部函数的引用,以使特定类型与重载行为相关联,而不会破坏我们的功能代码的纯度。

回顾 (Recap)

  • It’s possible to bring some disciplines from OOP into our functional code without breaking its purity.

    可以将OOP的某些学科带入我们的功能代码,而不会破坏其纯度。
  • Using references is an excellent way to implement ad-hoc-like polymorphism in TS.

    使用引用是在TS中实现类似ad-hoc的多态性的绝佳方法。

The scenario that I’ve used in this article is actually a simplified version of one that I found myself dealing with in my project, Rosebox, a styling library I’ve written in Typescript. Check it out.

我在本文中使用的场景实际上是我在自己的项目Rosebox中处理过的场景的简化版本, Rosebox是我用Typescript编写的样式库。 看看这个。

翻译自: https://levelup.gitconnected.com/polymorphism-in-typescript-59fad77f8cd7

无比打字与拼英打字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值