# 类型的计算
## Infer和强大的类型计算能力
Typescript提供了强大的类型计算能力。
不仅仅是……
联合
```ts
type Shape = Cirle | Rect | Triangle
```
求并集
```tsx
type A = { a : number, b : number }
type B = { a : number, c : number }
type C = A & B
// C 是 {a : number, b : number , c : number}
```
接口的联合
```ts
interface A {
foo() : void
}
interface A {
bar() : void
}
class X implements A {
foo(){
}
}
ERROR Class 'X' incorrectly implements interface 'A'.
Property 'bar' is missing in type 'X' but required in type 'A'.
```
## 而是更复杂的`infer`
思考如何解决这个问题的描述呢?
```ts
function flattern(arr){
}
```
这样可以吗?
```tsx
function flattern(arr : Array) : Array {
}
```
可以,但是——不够完整(好多any)
这样呢?
```tsx
type Flatterned = T extends (V)[] ? V : T
// Cannot find name 'V'
```
这句已经非常接近我们的语义了。
考虑下这样:
```tsx
type Flatterned = T extends (infer V)[] ? V : T
type D = Flatterned> // ? D
type E = Flatterned>> // ? E
```
如果:
```tsx
type Flatterned = T extends (infer V)[] ? Flatterned[] : T
type K = Flatterned>> // ? K
```
然后补全完整的程序:
```tsx
function flattern>(arr : T) : Array> {
return (new Array>())
.concat(
...arr.map(x => Array.isArray(x) ? flattern(x) : x)
)
}
```
`infer` 关键字告诉typescript V不是一个存在的类型,而是要推导的。
烧脑不?
看一个简单的做法:
```tsx
type Atom = string | boolean | number
type Nested = (T | (T | T[])[])[]
function flattern (arr : Nested) : Atom[] {
return (new Array()).concat(
...arr.map(x => Array.isArray(x) ? flattern(x) : x)
)
}
```
## 类型提取
`infer` 是一种类型的运算能力,在extends后面使用,让typescript去运算出目标类型。
```js
type Unwrapped = T extends (infer U)[] ? U : T
function first(arr : Array) : Unwrapped> {
return arr[0]
}
function first(arr : Array) : T {
return arr[0]
}
type T0 = Unwrapped> // string
```
出道题:如何把`Promise[]` 提取成`string[]`
先思考一个不够模块化的做法:
```tsx
type Unwrapped = T extends Array
? U extends Promise
? R[]
: U
: T
```
然后用这一个更加模块化的做法:
```tsx
e Unwrap = T extends Promise ? Unwrap
: T extends Array ?
UnwrapArray :
T
type UnwrapArray = T extends Array
? { [P in keyof T] : Unwrap }
: T
type T0 = Unwrap>[]>
```
## Vue Reactivity 源码解读(类型部分)
```tsx
import {UnwrapRef, reactive, ref, Ref} from 'vue'
type UnwrapNestedRefs = T extends Ref ? T : UnwrapRef
type D = UnwrapNestedRefs<{
x : Ref
}>
type E = UnwrapNestedRefs[>]
const d = reactive({
x : ref(0),
arr : [{
y : ref(0)
}]
})
const m = reactive([ref(0)])
const f = reactive(ref(0))
```
## 总结
思考题:如何去掉`Flatterned` 例子中的any?