Skip to content

关键字

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

InstanceType & thisType

Paramters & ConstructorParameters

ReturnType

Released under the MIT License.