使用 infer 和 typeof 在 Typescript 中创建工厂
Creating a Factory in Typescript using infer and typeof
主要目标:
我正在尝试学习(并理解,而不仅仅是复制和粘贴)如何在 Typescript 中创建工厂,但有一些与类型和类型推断相关的混淆点。我想
有一个“MyCloner”class 能够创建一个 IClonable 的多个实例。例如,如果我有一辆卡车 class 和一辆摩托车 class 都实现了 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 正在扩展函数“new”(据我所知这是一个保留关键字)。但是 R、T 和 'new' 是如何相互关联的呢?我不明白这里的 => 运算符是怎么回事(它是用来声明函数的吗?)
我不确定我在查找后是否理解推断在 Typescript 中的作用。
这是 the tutorial for ExtractInstanceType和上下文
我意识到将卡车保持为电动是额外的,据我所知通常不是工厂模式的一部分,但这是最终目标。但我认为,在了解了推断和 ExtractInstanceType 的基础知识之后,这应该不会是一个很大的进步。
感谢您的宝贵时间。
第二个混淆点(更多的类型声明和类型字面量):
我也对 the same tutorial 中的以下行感到困惑。
type userTypes = typeof userMap[Keys]; //typeof Developer | typeof Manager
对我来说,这似乎是在说 Keys 不是单个键?通常在 JS 中,我希望它是一个字符串,可以从字典中获取 return 中的单个值?但关键本质上是一个表示多种类型的类型文字,然后以某种方式用作单个键?
这里有Key供参考:
type Keys = keyof typeof userMap; // 'dev' | 'manager'
以后尝试将自己限制为每个问题一个问题,但您的问题的答案非常简洁,所以...
让我们将该条件类型声明转换为一些伪代码,以更清楚地指示正在发生的事情:
type InstanceType(T) = if T is a class then the type of the thing constructed by new
ing that class else type 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 satisfies the constraint that it represents a new
able thing that returns an R
' 而 R
就是 'the thing the class T
constructs'。 never
只是作为一种保障:以防调用者错误地使用非 class 泛型参数的类型。
现在我们有 几乎 句法有效的 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
是一个class 可以用 new
构造。 N.B。 AFAIK infer
只能 用于像这样的条件类型的上下文中。
type Keys = keyof typeof userMap;
这里我们要根据valueuserMap
中的key构造一个type。由于我们不能将值用作类型,因此我们必须调用 typeof
来获取 userMap 的类型,并且由于它是关联数据结构,我们可以调用 keyof
来获取 联合 的地图键:'dev' | 'manager'
.
然后剩下的就到位了,我们可以使用索引类型来获取值类型的并集(在 key/value 对意义上)来自地图:
type userTypes = typeof userMap[Keys];
您可能会认为是 Developer | Manager
,但由于我们正在构造一个 type (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
主要目标: 我正在尝试学习(并理解,而不仅仅是复制和粘贴)如何在 Typescript 中创建工厂,但有一些与类型和类型推断相关的混淆点。我想 有一个“MyCloner”class 能够创建一个 IClonable 的多个实例。例如,如果我有一辆卡车 class 和一辆摩托车 class 都实现了 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 正在扩展函数“new”(据我所知这是一个保留关键字)。但是 R、T 和 'new' 是如何相互关联的呢?我不明白这里的 => 运算符是怎么回事(它是用来声明函数的吗?)
我不确定我在查找后是否理解推断在 Typescript 中的作用。
这是 the tutorial for ExtractInstanceType和上下文
我意识到将卡车保持为电动是额外的,据我所知通常不是工厂模式的一部分,但这是最终目标。但我认为,在了解了推断和 ExtractInstanceType 的基础知识之后,这应该不会是一个很大的进步。
感谢您的宝贵时间。
第二个混淆点(更多的类型声明和类型字面量):
我也对 the same tutorial 中的以下行感到困惑。
type userTypes = typeof userMap[Keys]; //typeof Developer | typeof Manager
对我来说,这似乎是在说 Keys 不是单个键?通常在 JS 中,我希望它是一个字符串,可以从字典中获取 return 中的单个值?但关键本质上是一个表示多种类型的类型文字,然后以某种方式用作单个键?
这里有Key供参考:
type Keys = keyof typeof userMap; // 'dev' | 'manager'
以后尝试将自己限制为每个问题一个问题,但您的问题的答案非常简洁,所以...
让我们将该条件类型声明转换为一些伪代码,以更清楚地指示正在发生的事情:
type InstanceType(T) = if T is a class then the type of the thing constructed by
new
ing that class else typenever
让我们逐渐回到实际代码(这些都是同一事物的表示):
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 satisfies the constraint that it represents a new
able thing that returns an R
' 而 R
就是 'the thing the class T
constructs'。 never
只是作为一种保障:以防调用者错误地使用非 class 泛型参数的类型。
现在我们有 几乎 句法有效的 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
是一个class 可以用 new
构造。 N.B。 AFAIK infer
只能 用于像这样的条件类型的上下文中。
type Keys = keyof typeof userMap;
这里我们要根据valueuserMap
中的key构造一个type。由于我们不能将值用作类型,因此我们必须调用 typeof
来获取 userMap 的类型,并且由于它是关联数据结构,我们可以调用 keyof
来获取 联合 的地图键:'dev' | 'manager'
.
然后剩下的就到位了,我们可以使用索引类型来获取值类型的并集(在 key/value 对意义上)来自地图:
type userTypes = typeof userMap[Keys];
您可能会认为是 Developer | Manager
,但由于我们正在构造一个 type (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