类型推断
TS 能根据一些简单的规则推断变量的类型
// 1.从右向左(变量类型可以由定义推断)
let a = 1; // number
let bar = 'zhangsan'; // string
// 2.底部流出(返回值能被 return 语句推断)
function add(a: number, b: number) {
return a + b;
}
let c = add(1, 3); // number
// 3.从左向右(函数参数类型/返回值类型也能通过赋值来推断)
let fn = (a, b) => a + b;
type Sum = (a: number, b: number) => number;
let sum: Sum = fn; // 返回数字类型
type Sum2 = (a: string, b: string) => string;
let sum2: Sum2 = fn; // 返回字符串类型
// 4.结构化、解构
let person = {
name: 'zhufeng',
age: 11
}
let { name, age } = person;
// let name: string
// let age: number
// 5.DefaultProps
interface DefaultProps {
name?: string;
age?: number;
}
let defaultProps: DefaultProps = {
name: '张三',
age: 10
}
let props = { ...defaultProps, home: '北京' }
type Props = typeof props;
// type Props = {
// home: string;
// name?: string;
// age?: number;
// }
// 6.小心使用返回值
const addOne = (a: any) => a + 1;
let a = addOne(1); // any
const sum3 = (a: number, b: number) => a + addOne(b) as number;
let k = sum3(1, 2); // number
typeof
let obj = { name: '张三', age: 10 }
type P4 = typeof obj;
// type P4 = {
// name: string;
// age: number;
// }
索引访问操作符
interface Person {
name: string;
age: number;
job: {
name: string;
}
}
let newJob: Person['job'] = { name: '前端' };
映射类型
interface Person {
name: string;
age: number;
gender: 'male' | 'female'
}
type Partial<T> = {
// 批量把一个接口中的属性全部变成可选的
[key in keyof T]?: T[key]
}
// 测试
type PPerson = Partial<Person>
// type PPerson = {
// name?: string;
// age?: number;
// gender?: 'male' | 'female';
// }
keyof 操作符
keyof 简介
用于获取某种类型的所有键,其返回类型是联合类型
- 用于接口
interface Person { name: string; age: number; location: string; } type K1 = keyof Person; // "name" | "age" | "location" type K2 = keyof Person[]; // number | "length" | "push" | "concat" | ... type K3 = keyof { [x: string]: Person }; // string | number
- 用于类
class Person { name: string = "Semlinker"; } let sname: keyof Person; sname = "name";
- 用于基本数据类型
let K1: keyof boolean; // let K1: "valueOf" let K2: keyof number; // let K2: "toString" | "toFixed" | "toExponential" | ... let K3: keyof symbol; // let K1: "valueOf" | ...
keyof 的作用
- JavaScript 是一种高度动态的语言,有时在静态类型系统中捕获某些操作的语义可能会很棘手,用 keyof 和泛型能很好的解决问题;
- 示例代码:用于获取某个对象中指定属性的属性值,期望用户输入的属性是对象上已存在的属性:
function prop<T extends object, K extends keyof T>(obj: T, key: K) { return obj[key]; } // 测试 type Todo = { id: number; text: string; done: boolean; } const todo: Todo = { id: 1, text: "Learn TypeScript keyof", done: false } const id = prop(todo, "id"); // const id: number const text = prop(todo, "text"); // const text: string const done = prop(todo, "done"); // const done: boolean const date = prop(todo, "date"); //当访问 todo 对象上不存在的属性时,会报错 //类型 "date" 的参数不能赋给类型“keyof Todo”的参数
keyof 与 typeof 结合使用
获取对象所有的 key 值的联合类型
const COLORS = {
red: 'red1',
blue: 'blue1'
}
// 通过 typeof 操作符获取 COLORS 变量的类型,keyof 操作符获取该类型的所有键
// 即字符串字面量联合类型 'red' | 'blue'(获取 COLORS 所有的 key 值)
type Colors = keyof typeof COLORS
let color: Colors;
color = 'red' // Ok
color = 'blue' // Ok
color = 'yellow' // 不能将类型 "yellow" 分配给类型 "red" | "blue"
条件类型
- 条件类型
interface Fish { name1: string; } interface Water { name2: string; } interface Bird { name3: string; } interface Sky { name4: string; } // 1.条件类型的分发(必须是裸类型) type Condition<T> = T extends Fish ? Water : Sky; let con1: Condition<Fish | Bird> = { name2: '' }; let con2: Condition<Fish | Bird> = { name4: '' }; // 2.条件类型的分发(分发失效,因为 不是裸类型) type Condition2<T> = { t: T } extends { t: Fish } ? Water : Sky; let con3: Condition2<Fish | Bird> = { name2: '' }; // 不能将类型“{ name2: string; }”分配给类型“Sky” let con4: Condition2<Fish | Bird> = { name4: '' }; // 3.找出 T 中不包含 U 的部分 type Diff<T, U> = T extends U ? never : T; type R = Diff<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // never | never | never | 'd' => 'd' // 4.找出 T 中包含 U 的部分 type Filter<T, U> = T extends U ? T : never; type R3 = Filter<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // 'a' | 'b' | 'c'
- 内置条件类型
// 1.找出 T 中不包含 U 的部分 type Exclude<T, U> = T extends U ? never : T; type R4 = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // 2.找出 T 中包含 U 的部分 type Extract<T, U> = T extends U ? T : never; type R5 = Extract<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // 3.找到非空的部分 type NonNullable<T> = T extends null | undefined ? never : T; type R6 = NonNullable<'a' | 1 | null | undefined>; // 4.返回值类型 type ReturnType<T> = T extends (...args: any[]) => infer R ? R : T; const getUser = () => ({ name: '张三', age: 10 }); type ReturnUser = ReturnType<typeof getUser>; // type ReturnUser = { // name: string; // age: number; // } // 5.参数类型,infer 为类型推断 type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never; const getUser = (a: string, b: number) => ({ name: '张三', age: 10 }); type ParamsType = Parameters<typeof getUser>; // [a: string, b: number]
class Person { name: string; constructor(name: string) { this.name = name; } getName() { console.log(this.name); } } // 6.获取类的构造函数的参数类型 type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never; type Params = ConstructorParameters<typeof Person>; // 7.获取构造函数类型的实例类型 type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any; type Person8Instance = InstanceType<typeof Person>;
// 8.将 interface 中的属性全部变成可选属性 interface Company { id: number; name: string; } interface Person { id: number; name: string; company: Company } // 手动实现可选递归(+? 变成可选) type DeepPartial<T> = { [U in keyof T]+?: T[U] extends object ? DeepPartial<T[U]> : T[U] } // 测试 type PartialPerson = DeepPartial<Person>; let p: PartialPerson = { id: 1, name: '张三', company: { id: 2 } }
// 9.将 interface 中的属性全部变成必选属性 interface Person { name: string; age?: number; } // (-? 变成必选) type Required<T> = { [P in keyof T]-?: T[P]; }; // 测试 type RequiredPerson = Required<Person>; let p: RequiredPerson = { name: '张三', age: 11 }
// 10.将 interface 中的属性全部变成只读属性 interface Person { name: string; age: number; } type Readonly<T> = { readonly [P in keyof T]: T[P]; }; // 测试 type ReadOnlyNamePerson = Readonly<Person>; let p: ReadOnlyNamePerson = { name: '张三', age: 11 } p.name = '李四'; // 无法分配到 "name" ,因为它是只读属性 p.age = 11; // 无法分配到 "age" ,因为它是只读属性
// 11.Pick 从传入属性选取某些属性返回 interface Person { name: string; age: number; gender: number } type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; // 测试 let person: Person = { name: '张三', age: 11, gender: 1 }; type PickPerson = Pick<Person, 'name' | 'age'>; // type PickPerson = { // name: string; // age: number; // }
// 12.Extract 找出 T 中包含 U 的部分(条件类型分发) type Extract<T, U> = T extends U ? T : never; // 测试 type E = Extract<string | number | boolean, string | number>; // type E = string | number
// 13.Record 定义一个对象的 key 和 value 类型 // keyof any => string | number | symbol 联合类型 type Record<K extends keyof any, T> = { [xxx in K]: T; }; // 测试,key 是 string | number,value 是 string let k: Record<string | number, string> = { name: '张三', age: '11' };
自定义高级类型
Proxy 代理
type Proxy<T> = {
get(): T,
set(value: T): void;
}
type Proxify<T> = {
[P in keyof T]: Proxy<T[P]>
}
function proxify<T>(obj: T): Proxify<T> {
let result = <Proxify<T>>{};
for (const key in obj) {
Object.defineProperty(result, key, {
get: () => {
return obj[key];
},
set: (value) => {
obj[key] = value;
}
});
}
return result;
}
// 测试
let proxyProps: any = proxify<{ name: string, age: number }>({ name: '张三', age: 18 });
console.log(proxyProps); // {}
console.log(proxyProps.name); // 张三
proxyProps.name = '李四';
proxyProps.age = 20;
console.log(proxyProps.name); // 李四
SetDifference 差集
// 差集 A-B = Exclude
type SetDifference<A,B>= A extends B ?never:A;
// 测试
type A = string|number;
type B = number|boolean;
type AB = SetDifference<A,B>;
// type AB = string
Omit 去除指定的属性
type SetDifference<A,B>= A extends B ?never:A;
type Omit<T, K extends keyof any> = Pick<T, SetDifference<keyof T, K>>;
// 测试
type Props = { name: string, age: number, visible: boolean };
type OmitAgeProps = Omit<Props, 'age'>;
// type OmitAgeProps = {
// name: string;
// visible: boolean;
// }
Diff 获取两个类型差异的部分
type SetDifference<A, B> = A extends B ? never : A;
type Diff<T extends object, U extends object> = Pick<T, SetDifference<keyof T, keyof U>>;
// 测试
type Props = { name: string, age: number, visible: boolean };
type DefaultProps = { age: number };
type DiffProps = Diff<Props, DefaultProps>;
// type DiffProps = {
// name: string;
// visible: boolean;
// }
Intersection 获取两个类型的交集部分
type InterSection<T extends object, U extends object> =
Pick<T, Extract<keyof T, keyof U> & Extract<keyof U, keyof T>>;
// 测试
type Props = { name: string, age: number, visible: boolean };
type DefaultProps = { age: number };
type DuplicateProps = InterSection<Props, DefaultProps>;
// type DuplicateProps = {
// age: number;
// }
Overwrite 覆盖同一属性类型
type Diff<T extends object, U extends object> = Pick<T, SetDifference<keyof T, keyof U>>;
type InterSection<T extends object, U extends object> =
Pick<T, Extract<keyof T, keyof U> & Extract<keyof U, keyof T>>;
type Overwrite<T extends object, U extends object, I = Diff<T, U> & InterSection<U, T>> =
Pick<I, keyof I>
// 测试
type OldProps = { name: string, age: number, visible: boolean };
type NewProps = { age: string, other: string };
type ReplacedProps = Overwrite<OldProps, NewProps>;
// type ReplacedProps = {
// name: string;
// age: string;
// visible: boolean;
// }
Merge 合并
type SetDifference<A, B> = A extends B ? never : A;
type Omit<T, K extends keyof any> = Pick<T, SetDifference<keyof T, K>>;
// 浅拷贝一个属性类型
type Compute<A extends any> = A extends Function ? A : { [K in keyof A]: A[K] }
type Merge<O1 extends object, O2 extends object> = Compute<O1 & Omit<O2, keyof O1>>
// 测试
type O1 = {
id: number;
name: string
}
type O2 = {
id: number;
age: number;
}
type R2 = Merge<O1, O2>;
// type R2 = {
// id: number;
// name: string;
// age: number;
// }
类型保护
上一篇