TS 进阶1

You, TypeScript
Back

用泛型 "保存" 索引类型 K extends keyof T

/** 进阶: 用泛型保存索引类型
* K extends keyof T
* 这里其实通过 extends 关键字来约束了 K 的类型
*/
function pickValues<T, K extends keyof T> (obj: T, keys: K[]): T[K][] {
return keys.map((key) => {
return obj[key];
})
}

使用 in 关键字来快速生成索引类型 [K in keyof T]: T[K]

/** 映射类型: Mapped Types */
// 从原有类型中映射出来的类型,
// 由于要对类型中的 key 进行处理, 通常需要使用 in 操作符来遍历类型的索引 (key)
// [K in keyof T]: T[K]
// example 某个克隆的类型
type Clone<T> = {
[K in keyof T]: T[K]
}
// 实现一些TS内部的映射类型
type Partial<T> = {
[K in keyof T]? : T[K]
}
type Readonly<T> = {
readonly [K in keyof T]?: T[K]
}

条件类型

/** 条件类型: Conditional Types
条件类型的语法其实就是三元表达式, 通常用于 通过对泛型进行判断来给出类型.
Why?
泛型约束:
对于类型无法即时确定的场景, 使用条件类型来在 动态地 确定最终的类型
这样我们编写的函数被他人使用时, 就能根据他人使用时传入的参数来动态确定类型.
注意事项: 何时条件类型系统可以收到足够的信息来确定类型.
*/
// example1: 使用条件类型实现泛型约束的例子:
declare function strOrNumber<T extends boolean> (x: T): T extends true? string: number;
const strReturnType = strOrNumber(true)
const numReturnType = strOrNumber(false)
// example2
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? 'boolean'
: T extends undefined
? 'undefined'
: T extends Function
?'function'
: "object"
type y = TypeName<string>

分布式条件类型

ref: Distributive conditional types

Conditional types in which the checked type is a naked type parameter are called distributive conditional types. Distributive conditional types are automatically distributed over union types during instantiation.

{
/** 分布式条件类型: Distributive Conditional Types
> [ref: Distributive conditional types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types)
分布式条件类型是条件类型的特性之一, 如果条件类型的类型参数是裸类型联合 (没有再被包一层的类型 , 例如 [Type] 就不是裸类型了) , 条件类型会在实例化时期自动分发到联合类型上.
*/
type Naked<T> = T extends boolean? "Y": "N";
type Wrapped<T> = [T] extends [boolean] ? "Y" : "N";
/**
* 类型判断流程: 条件类型的 类型参数是 裸类型联合:
* 首先分发为两个类型: Naked<number> | Naked<boolean>
* 然后进行类型判断, 得到 "N" | "Y"
* */
type Distributed = Naked< number | boolean>;
/**
* 类型判断流程: 条件类型的 类型参数 不是 🙅🏻‍ 裸类型联合:
* 直接进行类型的判断 [number | boolean] extends [boolean]?
* 始终为 false, 所以得到 "N"
* */
// extends [boolean] 始终是 falsy 的
type NotDistributed = Wrapped<number | boolean>;
// 一句话概括: 如果条件类型的类型参数是 "没有被额外包装的联合类型参数", 那么在条件类型进行判定时, 会将联合类型分发, 得到多个 条件类型的联合
}

使用 infer 关键字来"提取"类型

/** infer 关键字
* 如果我们在一个函数类型中, 定义了返回值类型, 那么可以用 infer
来 "提取" 到这个函数的返回值类型
*/
const foo = (): string => {
return '123'
}
/** 在已有函数的情况下, 如何得到提取出函数返回值的类型?
* 实例: 定义一个 ReturnType<T> 来提取函数返回值类型
*/
type ReturnType<T> = T extends (...args: any[]) => infer R? R: any
type fooResult = ReturnType<typeof foo>
// 更严谨一点: 约束 ReturnType 的泛型为函数类型
type BetterReturnType<T extends (...args: any[]) => any > = T extends (...args: any[]) => infer R? R: any
© Apolo Du.