使用推断和typeof在Typescript中创建工厂



主要目标:我正在努力学习(并理解,而不仅仅是复制和粘贴)如何在Typescript中创建工厂,但在类型和类型推理方面存在一些困惑。我想有一个";MyCloner";类能够创建一个IClonable的多个实例。例如,如果我有一个Truck类和一个Motorcycle类,它们都实现IClonable。

我希望能够做一些类似的事情:

const vehicleCloner = new MyCloner();
const truck = new Truck({color: 'red', fuel: 'electric'});

和MyCloner做了一些类似的事情:

var myTenElectricTrucks = vehicleCloner.cloneWithRandomColors(truck, 10);

困惑的第一点(推断和新):我一直在学习一些教程,但我并不完全理解:

type ExtractInstanceType<T> = T extends new () => infer R ? R : never;

我想我不习惯这种类型的声明,因为一切都在进行。我知道我们正在声明某种类型,看起来有能力接受一个名为T的泛型。然后看起来T正在扩展函数";新的";(据我所知,这是一个保留关键字)。但是R、T和"new"是如何相互联系的呢?我不明白这个=>这里的运算符(它是用来声明函数的吗?)

在查了打字本之后,我不确定我是否理解推理在打字本中的作用。

以下是ExtractInstanceType和上下文的教程

我意识到保持卡车的电动化是额外的,据我所知,这不是工厂模式的一部分,但这是最终的目标。但我认为,在理解了推断和ExtractInstanceType的基础知识后,这应该不是一大步。

谢谢你抽出时间。

混淆的第二点(更多的类型声明和类型文字):

我也被同一教程中的下面一行弄糊涂了。

type userTypes = typeof userMap[Keys]; //typeof Developer | typeof Manager

对我来说,这似乎是在说钥匙不是一把钥匙?通常在JS中,我希望它是一个字符串,从字典中得到一个值作为回报?但键本质上是一个表示多个类型的类型文字,然后以某种方式用作单个键?

以下是供参考的密钥:

type Keys = keyof typeof userMap; // 'dev' | 'manager'

以后尽量把自己限制在每个问题一个问题,但问题的答案非常简洁,所以…

让我们将条件类型声明转换为一些更清楚地指示发生了什么的psuedo代码:

类型InstanceType(T)=如果T是一个类,则new通过该类构造的事物的类型否则类型never

让我们逐渐回到实际的代码(这些都是同一事物的表示):

type InstanceType<T> = (T is a class) ? (thing-T-constructs, i.e. 'R') : never
type InstanceType<T> = (T extends (new () => R)) ? R : never

希望逐行看到替换(就像简化数学方程式一样)会有所帮助。T extends new () => R只是意味着"T满足它表示返回R的可new事物的约束",而R只是"类T构造的事物"。never只是作为一种保护:以防调用方将类型与非类泛型参数一起使用不正确。

现在我们有了几乎语法有效的Typescript。但问题是R:它是一个未声明的变量,在类型中和在代码中一样有问题。这就是infer关键字的作用:

type InstanceType<T> = (T extends (new () => infer R)) ? R : never
// and dropping the grouping parens to arrive back at the original:
type InstanceType<T> = T extends new () => infer R ? R : never

在这里,我们告诉编译器根据所满足的条件来推断R的类型,即T是可以用new构造的类。注意,AFAIKinfer只能用于此类条件类型的上下文中。

type Keys = keyof typeof userMap;

在这里,我们想要基于userMap中的键来构造类型。由于我们不能使用值作为类型,我们必须调用typeof来获得userMap的类型,并且由于它是一个关联数据结构,我们可以调用keyof来获得映射键的并集'dev' | 'manager'

然后剩下的就就位了,我们可以使用索引类型从映射中获得值的类型的并集(在键/值对的意义上):

type userTypes = typeof userMap[Keys];

您可能会认为它是Developer | Manager,但由于我们正在构建类型(userTypes),并且我们不能将值用作类型,因此实际的并集是typeof Developer | typeof Manager

所以总结一下第二部分:

typeof userMap;       // Typescript compile-time type of the userMap
keyof typeof userMap; // The type of the *compile-time keys* of userMap
typeof userMap[keyof typeof userMap] // ditto but for the types of the *values* in the map

相关内容

  • 没有找到相关文章

最新更新