一、 unknown 和 any 的区别
- unknown 和 any 都是top type,但是 any 还同时是bottom type;
// 1. 任何类型都可以赋值给 unknown 和 any(包括彼此)
let a: unknown = 2;
let b: any = 3;
// any 也可以赋值给 unknown,unknown 也可以赋值给 any
a = b;
b = a;
// 2. unknown 只能赋值给 unknown 和 any
let c: number = a; // 报错,unknown 不能赋值给 number
let d: unknown = a; // 不报错,unknown 可以赋值给 unknown
// 3. any 可以赋值给任何类型
let e: number = b; // 不报错,any 可以赋值给 number
d = b; // 不报错,any 可以赋值给 unknown
- unknow 比 any 更安全。因为如果 unknown 没有先断言或者缩小到一个更具体的类型,则不允许对一个 unknown 进行任何操作(会报错)。
let a: unknown = 2;
console.log(a.toString()); // 报错,'a' is of type 'unknown'.
console.log(a++); // 报错,'a' is of type 'unknown'.
console.log((a as number).toString()); // 正常输出字符串'2'
二、手写一些 ts 的方法
1. Partial
type MyPartial<T> = {
[k in keyof T]?: T[k];
};
2. Pick<T, K>
使用:从T中挑选一组属性K组成新的类型。
interface A {
a: string;
b: number;
c: boolean;
}
type T = Pick<A, 'a' | 'b'>;
// type T = {a: string; b:number}
手写:
type MyPick<T, K extends keyof T> = {
[key in K]: T[key];
};
3. Exclude<T, U>
使用:提取存在于T但不存在于U的类型组成联合类型
type T1 = Exclude<string | number, number>; // T1 = string
type T2 = Exclude<'a' | 'b', 'a'>; // T2 = 'b'
手写:
type MyExclude<T, U> = T extends U ? never : T;
4. Extract<T, U>
使用:提取联合类型T和联合类型U的交集
type T = Extract<'a' | 'b', 'b' | 'c'>; // T = "b"
type T1 = Extract<string | number, number>; // T1 = number
手写:
type MyExtract<T, U> = T extends U ? T : never;
5. Omit<T, K>
使用:从T中剔除K的所有属性
interface A {
a: string;
b: number;
}
type T = Omit<A, 'a'>; // T={b:number}
手写:
type MyOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
6. Record<K extends keyof any, T>
使用:构造一个type,key为联合类型K中的子类型,类型为T
type T7 = Record<'a' | 'b', number>;
/*
T7 = {
a: number;
b: number;
}
*/
type T8 = Record<'a' | 'b', { name: string }>;
/*
T8 = {
a: {
name: string;
};
b: {
name: string;
};
}
*/
手写:
type MyRecord<K extends keyof any, T> = {
[key in K]: T;
};