泛型就是对类型进行编程。对比
type Partial<T> = {[P in keyof T]?: T[P];};function Partial(T) {// do something}
type => function,
在具体到使用上
// 传入 Person 参数,生成 student 类型,和 js 里面的函数调用几乎一致type student = Partial<Person>
以及在 js 代码中使用
// 在<T, U> 中定义了形参 T,U,然后在后面js 中使用function ids<T, U>(arg1: T, arg2: U): [T, U] {return [arg1, arg2];}
同样的,泛型也具有默认参数的概念
type A<T = string> = Array<T>;const aa: A = [1]; // type 'number' is not assignable to type 'string'.const bb: A = ["1"]; // okconst cc: A<number> = [1]; // ok
泛型接口
interface GenericIdentityFn<T> {(arg: T): T;}
泛型类
class GenericNumber<T> {zeroValue: T;add: (x: T, y: T) => T;}let myGenericNumber = new GenericNumber<number>();myGenericNumber.zeroValue = 0;myGenericNumber.add = function (x, y) {return x + y;};
泛型变量
是一个约定好的规范而已
- 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
type Func = typeof toArray; // -> (x: number) => number[]
比如设置了resolveJsonModule 编译选项后,导入 json文件里面的数据转化为类型,就可以使用 typeof 关键字```typescript// person.json{"id": "123","name": "asd"}//interface Students {list: typeof Person[]}
keyof
keyof 操作符可以用来一个对象中的所有 key 值:
interface Person {name: string;age: number;}type K1 = keyof Person; // "name" | "age"type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join"type K3 = keyof { [x: string]: Person }; // string | number
TODO: 如果想调试比较复杂的类型,是不是只能hover 在上面,根据提示获取具体有什么类型?这样不好调试,比如中间一些被忽略的,每次要跳层级进去
in
in 用来遍历枚举类型:
type Keys = "a" | "b" | "c"type Obj = {[p in Keys]: any} // -> { a: any, b: any, c: any }
infer
在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
以上代码中 infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用。
extends
继承
interface ILengthwise {length: number;}function loggingIdentity<T extends ILengthwise>(arg: T): T {console.log(arg.length);return arg;}
泛型工具类型
Partial
Partial<T> 的作用就是将某个类型里的属性全部变为可选项 ?。
源码
/*** Make all properties in T optional*/type Partial<T> = {[P in keyof T]?: T[P];};// 把 T 理解为函数的参数,通过 keyof T 拿到所有的属性名赋值给 P,通过 T[P] 获得相应的属性值。// 多的一部操作就是在中间增加一个 ? 号,变为了可选
Required
功能和Partial 相反,是将类型的属性变成必填, 这里的 -指的是去除。 -? 意思就是去除可选
/*** Make all properties in T required*/type Required<T> = {[P in keyof T]-?: T[P];};
Mutable
功能是将类型的属性变成可修改,这里的 -指的是去除。 -readonly 意思就是去除只读
type Mutable<T> = {-readonly [P in keyof T]: T[P];};
Readonly
/*** Make all properties in T readonly*/type Readonly<T> = {readonly [P in keyof T]: T[P];};
Pick
/*** From T, pick a set of properties whose keys are in the union K*/type Pick<T, K extends keyof T> = {[P in K]: T[P];};
Record
/*** Construct a type with a set of properties K of type T*/type Record<K extends keyof any, T> = {[P in K]: T;};
interface PageInfo {title: string;}type Page = "home" | "about" | "contact";const nav: Record<Page, PageInfo> = {about: { title: "about" },contact: { title: "contact" },home: { title: "home" },};
Exclude
/*** Exclude from T those types that are assignable to U*/type Exclude<T, U> = T extends U ? never : T;
Extract
/*** Extract from T those types that are assignable to U*/type Extract<T, U> = T extends U ? T : never;// 返回的是 Bird, 是从很多 类中提取出指定的类export type Alien = Extract<Person | Bird, Bird>
Omit
/*** Construct a type with the properties of T except for those in type K.*/type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
NonNullable
/*** Exclude null and undefined from T*/type NonNullable<T> = T extends null | undefined ? never : T;
ReturnType
里面有用到 infer
/*** Obtain the return type of a function type*/type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
Uppercase
/*** Convert string literal type to uppercase*/type Uppercase<S extends string> = intrinsic;
Lowercase
/*** Convert string literal type to lowercase*/type Lowercase<S extends string> = intrinsic;
TODO: intrinsic 是个什么东西? 大写小写都可用
Capitalize
/*** Convert first character of string literal type to uppercase*/type Capitalize<S extends string> = intrinsic;
解读 react 的一些 type
// node_modules\@types\react\index.d.tstype ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;interface StaticLifecycle<P, S> {getDerivedStateFromProps?: GetDerivedStateFromProps<P, S>;getDerivedStateFromError?: GetDerivedStateFromError<P, S>;}// ComponentClass 继承了 StaticLifecycle, 有getDerivedStateFromProps 和 getDerivedStateFromErrorinterface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {new (props: P, context?: any): Component<P, S>;propTypes?: WeakValidationMap<P>;contextType?: Context<any>;contextTypes?: ValidationMap<any>;childContextTypes?: ValidationMap<any>;defaultProps?: Partial<P>;displayName?: string;}interface FunctionComponent<P = {}> {// FunctionComponent 是一个函数,接受两个参数(props 和 context )返回 ReactElement 或者 null。// type PropsWithChildren<P> = P & { children?: ReactNode };(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;propTypes?: WeakValidationMap<P>;contextTypes?: ValidationMap<any>;defaultProps?: Partial<P>;// 函数组件的名字,一般在调试面板时候方便调试displayName?: string;}
ComponentType 由 ComponentClass 和 FunctionComponent 组合成
泛型递归
递归声明
单链表
type ListNode<T> = {data: T;next: ListNode<T> | null;};
TODO: 源码里面关于这段, new 的意思
/** Any HTML element. Some elements directly implement this interface, while others implement it via an interface that inherits it. */interface HTMLElement extends Element, DocumentAndElementEventHandlers, ElementCSSInlineStyle, ElementCSSInlineStyle, ElementContentEditable, GlobalEventHandlers, HTMLOrSVGElement {accessKey: string;readonly accessKeyLabel: string;...removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;}declare var HTMLElement: {prototype: HTMLElement;new(): HTMLElement;};
递归调用
递归地将类型中所有的属性都变成可选
type DeepPartial<T> = T extends Function? T: T extends object? { [P in keyof T]?: DeepPartial<T[P]> }: T;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
