关键字
typeof
将变量定义为类型(先定义变量, 再生成类型)
typescript
// 先定义变量
const user1 = {
id: 1001,
email: "1001@qq.com",
};
const user2 = {
id: 1002,
email: "1002@qq.com",
address: "ShangHai",
};
// 然后在定义类型, 类似
// type User = { id: number, email: string, [key: string]: any }
type User = typeof user1;
// 在使用这个类型的时候, 传入的对象,
// 这个对象必须拥有所有user1所拥有的key(id, email)
// 不可以少, 但是可以多(可以分别注释 id/email 和 address)
// 看看编译的报错
function getEmail(user: User, key: string): string {
console.log(user[key]);
}
keyof
可以获取接口的所有 key
typescript
interface IUser {
id: number;
email: string;
username: string;
password: string;
}
// 使用类型别名: 无法定义返回值类型
// 这个类型(IUserKey)的值只能是 IUser 这个接口的 key 字符串,类似:
// type IUserKey = "id" | "email" | "username" | "password"
// 定义这个类型的主要作用就是缩小范围, 如果定义为 string 的话, 那么
// 就没有精确的属性提示,可以是任意的值,也能通过编译,限制了之后, 就只能
// 是接口里定义的那几个 key 值, 而且就是把接口改了, 这个 IUserKey 也会自己更新
type IUserKey = keyof IUser;
function getAttribute(user: IUser, key: IUserKey) {
return user[key];
}
// 使用泛型也可以实现
// T继承 IUser 接口, K 继承接口的所有的 keyof IUser 的结果, 返回 T[K]
function getAttribute2<T extends IUser, K extends keyof IUser>(
obj: T,
key: K
): T[K] {
return obj[key];
}
const user1: IUser = {
id: 1001,
username: "tom",
email: "tom@qq.com",
password: "123456",
};
console.log(getAttribute(user1, "email"));
console.log(getAttribute2(user1, "username"));
extends
用户继承, 在 JS 中只能用来继承类, 但是在 TS 中, 可以用来继承接口, 继承联合类型
typescript
interface IUser {
id: number;
email: string;
password: string;
}
// 继承接口: ILogin extends IUser
interface ILoginInfo extends IUser {
token: string;
}
// 继承联合类型: T extends undefined | null
type NotNullable<T> = T extends undefined | null ? never : T;
// 继承 keyof 的结果: K extends keyof T
function getValue<T extends IUser, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
in
和 JS 中类似, in
操作符用于检测对象中的 key
, 如 for in
遍历对象的所有的 key
可用于联合类型, 也能用于 keyof 返回的结果
typescript
// 检测对象中的key
const obj = {
id: 1001,
};
console.log("id" in obj); // true
console.log("email" in obj); // false
// 用于联合类型
type TodoKeys = "id" | "completed" | "content";
type ToDo = {
[key in TodoKeys]: string;
};
// 用于 keyof 的结果(这里可以把keyof的结果看做一个联合类型)
type RO<T> = {
readonly [K in keyof T]: T[K];
};
infer
infer 关键字可以用于从一个类型中推断出另一个类型
typescript
// 推断数组的第一个元素的类型
type FirstOfArray<T extends any[]> = T extends [infer First, ...infer Rest] ? First : never;
// 推断返回的类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
NonNullable
非空属性泛型(剔除空属性泛型)
typescript
type NotEmpty = NonNullable<string | 0 | 1 | boolean | undefined | null>;
let t: NotEmpty = 1;
t = "";
t = 0;
t = false;
// NonNullable 只会过滤 null 和 undefined, 不会过滤 0 和 false 还有空字符串
// t = undefined; Type 'undefined' is not assignable to type 'NotEmpty'.
// t = null; Type 'null' is not assignable to type 'NotEmpty'.
Exclude & Extract
处理多个类型:
去除属性泛型 Exclude<T, U>
从T中去除U
提取属性泛型 Extract<T, U>
从 T 中提取 U
typescript
type T1 = Exclude<10 | null | string | (() => void), Function>;
let t: T1 = 10; // 这个 t 的值只能是任意字符串或者 10 或者 null ,不能是 Function
t = "tom";
t = "hello";
t = null;
// t = function () {
// console.log("test");
// }
// Type '() => void' is not assignable to type 'T1'.
type T1 = Extract<number | "show" | "hiden" | boolean, boolean>;
let t: T1 = true; // 只能赋值为 boolean 类型的值
t = false;
// t= 11;
// Type 'number' is not assignable to type 'T1'.
Partial & Required
所有 key 必选和可选, 挑选或删除属性构造新的类型
typescript
// 默认情况下: 只有id这1个必选项
interface IUser {
id: number;
email?: string;
password?: string;
}
// 用 Partial 泛型, 所有的key都是可选项
const u1: Partial<IUser> = {
email: "10001@qq.com",
};
// 用 Partial 泛型, 所有的key都是可选项
const u2: Required<IUser> = {
id: 10002,
email: "10002@qq.com",
password: "123456",
};
Pick && Omit
typescript
// 默认情况下, 3个属性都必须实现
interface IUser {
id: number;
email: string;
password: string;
}
// 用 Pick 其他属性全部删掉
// 只留下 email 属性来构造新的类型, 不能有其他属性
const u3: Pick<IUser, "email"> = {
email: "xxx",
};
// 用 Omit 删除掉 avatar 和 password
// 只留下 id 和 email 属性来 构造新的类型, 不能有其他属性
const u4: Omit<IUser, "password"> = {
id: 10004,
email: "222@qq.com",
};
Readonly & Writeable
- 只读属性
typescript
interface IUser {
id: number;
email: string;
password?: string;
}
// 用 Readonly 赋值后无法再修改
const u1: Readonly<IUser> = {
id: 1001,
email: "password",
};
// u1.id = 1111; // 无法修改
// 默认系统是没有 Writable 的, 因为默认是可读可写的,
// 但是我现在就是想让有 readonly 修饰过的属性变成可写的
interface IConfig {
readonly title: string;
readonly url: string;
}
type Writable<T> = {
-readonly [K in keyof T]: T[K];
};
const conf: Writable<IConfig> = {
title: "QQ",
url: "https://qq.com",
};
conf.title = "baidu";
conf.url = "https://baidu.com";
Record
同时约束 key 和 value 的类型
typescript
interface IUser {
id: number;
email: string;
readonly password: string;
avatar?: string;
}
// 使用 Record 泛型, 可以同时约束 key 和 value 的类型
// key 只能是数字或者 "tom" "jerry" 这两个字符串
// value 必须实现 IUser 接口类型
const users: Record<"tom" | "jerry" | number, IUser> = {
tom: {
id: 1001,
email: "1001@qq.com",
password: "1001@qq.com",
},
jerry: {
id: 1002,
email: "1002@qq.com",
password: "1002@qq.com",
avatar: "xxx.jpg",
},
1003: {
id: 1003,
email: "1003@qq.com",
password: "1001@qq.com",
},
};
Awaited
typescript