泛型就是对类型进行编程。对比

  1. type Partial<T> = {
  2. [P in keyof T]?: T[P];
  3. };
  4. function Partial(T) {
  5. // do something
  6. }

type => function, 传入参数 => (T)
在具体到使用上

  1. // 传入 Person 参数,生成 student 类型,和 js 里面的函数调用几乎一致
  2. type student = Partial<Person>

以及在 js 代码中使用

  1. // 在<T, U> 中定义了形参 T,U,然后在后面js 中使用
  2. function ids<T, U>(arg1: T, arg2: U): [T, U] {
  3. return [arg1, arg2];
  4. }

同样的,泛型也具有默认参数的概念

  1. type A<T = string> = Array<T>;
  2. const aa: A = [1]; // type 'number' is not assignable to type 'string'.
  3. const bb: A = ["1"]; // ok
  4. const cc: A<number> = [1]; // ok

泛型接口

  1. interface GenericIdentityFn<T> {
  2. (arg: T): T;
  3. }

泛型类

  1. class GenericNumber<T> {
  2. zeroValue: T;
  3. add: (x: T, y: T) => T;
  4. }
  5. let myGenericNumber = new GenericNumber<number>();
  6. myGenericNumber.zeroValue = 0;
  7. myGenericNumber.add = function (x, y) {
  8. return x + y;
  9. };

泛型变量

是一个约定好的规范而已

  • T(Type):表示一个 TypeScript 类型
  • K(Key):表示对象中的键类型
  • V(Value):表示对象中的值类型
  • E(Element):表示元素类型

    一些关键字

    TypeScript 内置了一些常用的工具类型,比如 Partial、Required、Readonly、Record 和 ReturnType 等。除此之外还提供了一些操作符

    typeof

    typeof 操作符可以用来获取一个变量声明或对象的类型。 ```typescript interface Person { name: string; age: number; }

const sem: Person = { name: ‘semlinker’, age: 30 }; type Sem= typeof sem; // -> Person

function toArray(x: number): Array { return [x]; }

type Func = typeof toArray; // -> (x: number) => number[]

  1. 比如设置了resolveJsonModule 编译选项后,导入 json文件里面的数据转化为类型,就可以使用 typeof 关键字
  2. ```typescript
  3. // person.json
  4. {
  5. "id": "123",
  6. "name": "asd"
  7. }
  8. //
  9. interface Students {
  10. list: typeof Person[]
  11. }

keyof

keyof 操作符可以用来一个对象中的所有 key 值:

  1. interface Person {
  2. name: string;
  3. age: number;
  4. }
  5. type K1 = keyof Person; // "name" | "age"
  6. type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join"
  7. type K3 = keyof { [x: string]: Person }; // string | number

TODO: 如果想调试比较复杂的类型,是不是只能hover 在上面,根据提示获取具体有什么类型?这样不好调试,比如中间一些被忽略的,每次要跳层级进去
image.png

in

in 用来遍历枚举类型:

  1. type Keys = "a" | "b" | "c"
  2. type Obj = {
  3. [p in Keys]: any
  4. } // -> { a: any, b: any, c: any }

infer

在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用。

  1. type ReturnType<T> = T extends (
  2. ...args: any[]
  3. ) => infer R ? R : any;

以上代码中 infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用。

https://itdashu.com/docs/typescriptlesson/2edda/infer.html

extends

继承

  1. interface ILengthwise {
  2. length: number;
  3. }
  4. function loggingIdentity<T extends ILengthwise>(arg: T): T {
  5. console.log(arg.length);
  6. return arg;
  7. }

泛型工具类型

Partial

Partial<T> 的作用就是将某个类型里的属性全部变为可选项 ?
源码

  1. /**
  2. * Make all properties in T optional
  3. */
  4. type Partial<T> = {
  5. [P in keyof T]?: T[P];
  6. };
  7. // 把 T 理解为函数的参数,通过 keyof T 拿到所有的属性名赋值给 P,通过 T[P] 获得相应的属性值。
  8. // 多的一部操作就是在中间增加一个 ? 号,变为了可选

Required

功能和Partial 相反,是将类型的属性变成必填, 这里的 -指的是去除。 -? 意思就是去除可选

  1. /**
  2. * Make all properties in T required
  3. */
  4. type Required<T> = {
  5. [P in keyof T]-?: T[P];
  6. };

Mutable

功能是将类型的属性变成可修改,这里的 -指的是去除。 -readonly 意思就是去除只读

  1. type Mutable<T> = {
  2. -readonly [P in keyof T]: T[P];
  3. };


Readonly

  1. /**
  2. * Make all properties in T readonly
  3. */
  4. type Readonly<T> = {
  5. readonly [P in keyof T]: T[P];
  6. };

Pick

  1. /**
  2. * From T, pick a set of properties whose keys are in the union K
  3. */
  4. type Pick<T, K extends keyof T> = {
  5. [P in K]: T[P];
  6. };

Record

  1. /**
  2. * Construct a type with a set of properties K of type T
  3. */
  4. type Record<K extends keyof any, T> = {
  5. [P in K]: T;
  6. };
  1. interface PageInfo {
  2. title: string;
  3. }
  4. type Page = "home" | "about" | "contact";
  5. const nav: Record<Page, PageInfo> = {
  6. about: { title: "about" },
  7. contact: { title: "contact" },
  8. home: { title: "home" },
  9. };

Exclude

  1. /**
  2. * Exclude from T those types that are assignable to U
  3. */
  4. type Exclude<T, U> = T extends U ? never : T;

Extract

  1. /**
  2. * Extract from T those types that are assignable to U
  3. */
  4. type Extract<T, U> = T extends U ? T : never;
  5. // 返回的是 Bird, 是从很多 类中提取出指定的类
  6. export type Alien = Extract<Person | Bird, Bird>


Omit

  1. /**
  2. * Construct a type with the properties of T except for those in type K.
  3. */
  4. type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

NonNullable

  1. /**
  2. * Exclude null and undefined from T
  3. */
  4. type NonNullable<T> = T extends null | undefined ? never : T;

ReturnType

里面有用到 infer

  1. /**
  2. * Obtain the return type of a function type
  3. */
  4. type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

Uppercase

  1. /**
  2. * Convert string literal type to uppercase
  3. */
  4. type Uppercase<S extends string> = intrinsic;

Lowercase

  1. /**
  2. * Convert string literal type to lowercase
  3. */
  4. type Lowercase<S extends string> = intrinsic;

TODO: intrinsic 是个什么东西? 大写小写都可用

Capitalize

  1. /**
  2. * Convert first character of string literal type to uppercase
  3. */
  4. type Capitalize<S extends string> = intrinsic;

解读 react 的一些 type

  1. // node_modules\@types\react\index.d.ts
  2. type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
  3. interface StaticLifecycle<P, S> {
  4. getDerivedStateFromProps?: GetDerivedStateFromProps<P, S>;
  5. getDerivedStateFromError?: GetDerivedStateFromError<P, S>;
  6. }
  7. // ComponentClass 继承了 StaticLifecycle, 有getDerivedStateFromProps 和 getDerivedStateFromError
  8. interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
  9. new (props: P, context?: any): Component<P, S>;
  10. propTypes?: WeakValidationMap<P>;
  11. contextType?: Context<any>;
  12. contextTypes?: ValidationMap<any>;
  13. childContextTypes?: ValidationMap<any>;
  14. defaultProps?: Partial<P>;
  15. displayName?: string;
  16. }
  17. interface FunctionComponent<P = {}> {
  18. // FunctionComponent 是一个函数,接受两个参数(props 和 context )返回 ReactElement 或者 null。
  19. // type PropsWithChildren<P> = P & { children?: ReactNode };
  20. (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
  21. propTypes?: WeakValidationMap<P>;
  22. contextTypes?: ValidationMap<any>;
  23. defaultProps?: Partial<P>;
  24. // 函数组件的名字,一般在调试面板时候方便调试
  25. displayName?: string;
  26. }

ComponentType 由 ComponentClass 和 FunctionComponent 组合成

泛型递归

递归声明

单链表

  1. type ListNode<T> = {
  2. data: T;
  3. next: ListNode<T> | null;
  4. };

TODO: 源码里面关于这段, new 的意思

  1. /** Any HTML element. Some elements directly implement this interface, while others implement it via an interface that inherits it. */
  2. interface HTMLElement extends Element, DocumentAndElementEventHandlers, ElementCSSInlineStyle, ElementCSSInlineStyle, ElementContentEditable, GlobalEventHandlers, HTMLOrSVGElement {
  3. accessKey: string;
  4. readonly accessKeyLabel: string;
  5. ...
  6. removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
  7. removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
  8. }
  9. declare var HTMLElement: {
  10. prototype: HTMLElement;
  11. new(): HTMLElement;
  12. };

递归调用

递归地将类型中所有的属性都变成可选

  1. type DeepPartial<T> = T extends Function
  2. ? T
  3. : T extends object
  4. ? { [P in keyof T]?: DeepPartial<T[P]> }
  5. : T;
  6. type PartialedWindow = DeepPartial<Window>; // 现在window 上所有属性都变成了可选

https://zhuanlan.zhihu.com/p/147248333 Typescript复杂泛型实践:如何切掉函数参数表的最后一个参数? https://lucifer.ren/blog/2020/06/16/ts-generics/ 你不知道的 TypeScript 泛型(万字长文,建议收藏) https://itdashu.com/docs/typescriptlesson/2edda/is.html