# TypeScript 挑战
# keyof
keyof用来返回属性的联合类型
type objType = { name: string; age: number };
type keyofType = keyof objType; // 类型为name|age
// 不能直观看到结果,可以用辅助类型来看
type DirectKeys<T> = T extends any ? T : never;
type getKeyofType = DirectKeys<keyofType>; //name | age
type TypeAny = keyof any; // 等同于string|number|symbol,固定结果
# in
in用来迭代联合类型
type K = {
name: string;
age: number;
phone: number;
};
// 给每一个属性添加?
type KType = {
[P in keyof K]+?: K[P];
// 等同于
// name?: K['name'] = string;
// age?: K['age']=number;
// phone?: K['phone']=number;
};
# 加号和减号
-: 去掉可选
type Required<T> = {
[K in keyof T]-?: T[K];
};
type S = {
a: number;
b?: number;
type RequiredS = Required<S>; // {a:number,b:number}
type Read<T> = {
// 非只读
-readonly [K in keyof T]: T[K];
};
+: 添加可选,可以忽略不写
type Partial<T> = {
[K in keyof T]+?: T[K];
};
type S = {
a: number;
b?: number;
};
type Partial = Partial<S>; // {a?:number,b?:number}
# extends
类型约束,限制 T 只能为联合类型(keyof U)中的一种
T extends keyof U
条件类型 根据符合条件返回
T extends U ? T :never
T 如果是联合类型,会逐个进行比较,将最后的结果合并
// 通过T来进行extends,会使里面的类型逐个进行比较,返回的类型会逐个合并
type Tcond<T> = T extends string | number ? T : never;
type TextTcond = Tcond<string | number | boolean>; // string|number
获取两个类型的共同类型
type T1 = "name" | "age" | "sex";
type T2 = "name" | "address";
// 通过迭代去判断是否有交集
type Extract<T, P> = T extends P ? T : never;
type R = Extract<T1, T2>;
# infer
设置占位符,用于使用的时候获取对应的类型
type CarType = (params: Car) => string;
// A extends B,判断A类型是否属于B类型
// 获取Car类型
type getCarP = CarType extends (params: infer P) => string ? P : CarType;
// 获取string类型
type getCarR = CarType extends (params: Car) => infer R ? R : CarType;
# typeof
获取变量的类型
function fn(a: number): number {
return a;
}
type Tf = typeof fn; // (a:number)=>number
# Pick
从类型 T 中选出符合 K 的属性,构造一个新的类型。
interface Todo {
title: string;
description: string;
completed: boolean;
}
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
type TodoPreview = MyPick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
# readonly
Readonly 是用来让所有属性变为只读,其用法为:
interface Todo {
title: string;
description: string;
}
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
};
const todo: MyReadonly<Todo> = {
title: "Hey",
description: "foobar",
};
// 给定接口类型中需添加新的类型
interface I1 {
a: string;
b: number;
}
type TAddI1<T, K extends string, V> = {
[P in keyof T | K]: P extends keyof T ? T[P] : V;
};
type TI1 = TAddI1<I1, "c", boolean>;
// 去除key
type Module = {
a: string | number;
b: boolean | string;
};
type DeleteModule<T> = {
[Key in keyof T]: T[Key];
}[keyof T]; // 如果不要key,直接后面加
type GetDeleteModule = DeleteModule<Module>;
// 模版
type template = {
a: string;
b: string;
c: string;
};
type Ttemplate<T, U> = `${T & string} / ${U & string}`;
type template_<T> = {
[Key in keyof T]: Ttemplate<Key, T[Key]>;
};
type TTtemplate = template_<template>;
// Extract 就是 T extends U ? T : never 的简写,底层实现
type TExtract = Extract<string, string | number>; // string
// Exclude = T extends U ? never : T
type TestExclude = Exclude<string, string | number>; // never
// Record,比object更加灵活,支持string|number|symbol,对象或者数组
function rec(obj: Record<string, any>) {
console.log(obj);
}
let recData = rec({ age: "1" });
// 数组也支持"0":1
let recData2 = rec([1, 2]);
// Pick,抓取类型,接口,类中的所需要的属性组成一个对象类型
interface P {
a: string;
b: number;
c: boolean;
}
type SubP = Pick<P, "a" | "b">;
// 映射 in,排除获取
interface P2 {
a: string;
b: number;
c: boolean;
}
type omit<T, K extends keyof T> = {
[P in keyof T as Exclude<P, K>]: T[P];
};
// 排除c
type getOmit = omit<P2, "c">; // {a:string,b:number}
// Capitalize,首字母转化成大写
type C = "a";
type getC = Capitalize<C>;
// -? 去掉可选
type Required<T> = {
[K in keyof T]-?: T[K];
};
// ? 添加可选
type Partial<T> = {
[K in keyof T]+?: T[K];
};
// -readonly 去除只读
type Read<T> = {
// 只读
// readonly [K in keyof T]: T[K]
// 非只读
-readonly [K in keyof T]: T[K];
};