有没有办法提供类似于 Rust 枚举的多态类型区分?



在Rust中进行了大量编码后,我最近回到了JS/TS,这是我非常怀念的功能。

所以假设我有一个值,它可能是Cat的实例,也可能是Dog的实例,根据它来自哪个类,我想执行不同的逻辑。由于Javascript不能执行classname ==(我想是?(,所以我通常所依赖的也是传递一个字符串来指示类,如下所示:

function groomAnimal(animal: Cat | Dog, animalType: 'cat' | 'dog') {
if (animalType === 'cat') {
(animal as Cat).trimNails();
} else {
(animal as Dog).trimFur();
}
}

我讨厌这样,因为它很难处理,而且编译器不能保证调用方正确地履行约定。另一方面,在Rust中,这将是非常优雅的:

enum Animal {
Cat(CatData),
Dog(DogData),
}
fn groomAnimal(animal: Animal) {
match animal {
Cat(catData) => catData.trimNails(),
Dog(dogData) => dogData.trimFur(),
}
}

基本上enum本身表示";类";,还持有";类";数据,从而获得数据和检查数据类型是相同的操作

typescript中是否有任何模式允许多态函数签名,同时确保代码在编译时对正确的数据类型进行操作?

保留一个单独的值来指示类型非常容易出错。如果CatDog是类类型(而不仅仅是接口(,则可以使用instanceof直接验证其类型:

class Cat {
trimNails() {}
}
class Dog {
trimFur() {}
}
function groomAnimal(animal: Cat | Dog) {
if (animal instanceof Cat) {
// animal must be Cat, so you can call trimNails()
animal.trimNails();
} else {
// animal must otherwise be a Dog, so you can call trimFur()
animal.trimFur();
}
}

您可以创建一个具有Cat/Dog和一些标识符属性的可组合结构,这与您的方法有点相似,但有所不同。

像这样的

type Animal = Cat & { animalType: 'Cat' } | Dog & { animalType: 'Dog' }

groomAnimal方法现在将采用组合结构

function groomAnimal(animal: Animal) {
if (animal.animalType === 'Cat') {
animal.trimNails();
} else {
animal.trimFur();
}
}

这里有一个小样本,我在其中创建了一个cat并将其传递给groomAnimal方法,

const tom = {
trimNails() {
console.log('Trimming nails')
}
}
groomAnimal({ ...tom, kind: 'Cat'})

在您的情况下,您说过您从一些api调用中解析这些。您可以在解析时准备好Animal/Animals[]对象,然后在整理时使用它。

当然,正如您从代码中看到的那样,编译器可以保证调用者实际上正确地履行了约定。

最新更新