高级 TypeScript 练习 - 答案 1
我问的问题是:
如果我们有一个像 这样的包装类型
Promise
,那么我们如何获取包装类型内部的类型呢?例如,如果我们有 ,Promise<ExampleType>
该如何获取ExampleType
?
答案
type Transform<A> = A extends Promise<infer Inner> ? Inner : never
type Result = Transform<Promise<string>> // Result is string type
为了解开承诺类型,我们使用了infer
关键字。
关键字对任何类型构造函数都有帮助,类型构造函数是由另一个类型变量参数化的类型,因此任何具有通用占位符的类型,如A<B>
,其中A
类型构造函数由参数化B
。
使用示例infer
我们infer
也可以与其他类型一起使用,例如数组
type InsideArray<A> = A extends Array<infer Inside> ? Inside : never
type Str = InsideArray<Array<string>>; // Str is string
那么自定义参数化类型呢?可以!
type Surprise<A> = { inside: A }
type UnpackSurprise<S> = S extends Surprise<infer Inside> ? Inside : never
type Num = UnpackSurprise<Surprise<number>> // Num is number
我们甚至可以使用它infer
来获取映射类型属性
type User = {
id: number,
name: string,
}
type Doc = {
id: string,
}
type GetProperty<T, Prop extends keyof T> = T extends { [K in Prop]: infer Value } ? Value : never
type UserId = GetProperty<User, 'id'>
type DocId = GetProperty<Doc, 'id'>
问题:如何更简单地获取 Mapped 类型属性的类型?请在评论中写下你的答案!
我们可以使用多个类型变量并推断它们吗?当然可以!
type ABC<A, B, C> = { a: A, b: B, c: C }
type ABCIntoTuple<T>
= T extends ABC<infer A, infer B, infer C> ? [A, B, C] : never
type Example = ABC<string, boolean, number>
type ExampleTuple = ABCIntoTuple<Example> // [string, boolean, number]
在上面的例子中,我们推断出所有三个类型参数并将它们放入 3-n 元组中。
为什么never
?
类型never
是一种底层类型,它是一种没有任何值的类型,它非常方便地构造,用于表示我们的函数不返回,或者代码的某些路径无法访问,有关它的更多信息,您可以阅读Marius Schulz 的精彩文章。
我们使用never
条件语句来表示不愉快的路径,我们说这是一条死胡同,如果你不传递给构造函数特定的类型,我们就没有其他选择,我们的类型无法与任何其他类型兼容。想象一下,当我们传递给它一些不符合条件的内容时,它会如何表现:
type Transform<A> = A extends Promise<infer Inner> ? Inner : never
type OhGosh = Transform<string> // OhGosh evaluates to never
我们可以对负路径有不同的表示,但 never 是最佳选择,因为进一步的类型转换毫无意义。我们也可以在参数中设置约束,这样never
路径就永远不会到达。
考虑以下改变:
type Transform<A extends Promise<any>> = A extends Promise<infer Inner> ? Inner : never
type OhGosh = Transform<string> // compilation error
现在A extends Promise<any>
我们的实用程序类型Transform
是防弹的,因为对于不扩展的类型,编译将失败Promise<any>
。
我为什么要使用
Promise<any>
?
我把 放进any
去Promise
是因为any
是不健全的类型之一,也是可以分配给一切的类型,这意味着每个类型都从 扩展any
,这决定了每种Promise
类型都会扩展Promise<any>
本系列才刚刚开始。如果你想了解 TypeScript 高级教程中一些有趣的新问题,请在dev.to和Twitter上关注我。
文章来源:https://dev.to/macsikora/advanced-typescript-exercises-answer-1-59ge