类型学习
值到类型转换
- as const
// 数值
const type = ["primary", "secondary"] as const;
type buttonType = (typeof type)[number];
// type buttonType = "primary" | "secondary"
type IButton = { [key in buttonType]: string };
/* type IButton = {
primary: string;
secondary: string;
} */
- 枚举
enum type {
primary = "primary",
secondary = "secondary",
}
type buttonType = type;
type IButton = { [key in buttonType]: string };
// type IButton = {
// primary: string;
// secondary: string;
// }
常见场景:
- 创建组件样式映射(如本例)。
- 实现枚举到值的映射。
- 从配置数组自动生成类型定义。
优势
- 类型安全:任何不在 type 数组中的键都会导致编译错误。
- 可维护性:修改 type 数组时,类型系统会自动更新所有依赖。
- 代码简洁:避免手动重复书写类型定义。
类型条件
通过 extends 关键字加三目运算符来实现类型条件判断。
// 类型定义
interface Human {
creative: true;
name?: string;
}
interface Animal {
species: string;
}
type Creature = Human | Animal;
// 使用示例
const creature1 = { creative: true, name: "Alice" };
const creature2 = { species: "cat" };
// 类型判断
type species1 = typeof creature1 extends { creative: boolean } ? Human : Animal;
// type species1 = Human
type species2 = typeof creature2 extends { creative: boolean } ? Human : Animal;
// type species2 = Animal
泛型
泛型是指在定义函数、接口或类时,不指定具体的类型,而是在使用时再指定类型。
// 泛型定义
type creatureType<T> = T extends { creative: boolean } ? Human : Animal;
// 类型判断
type species1 = creatureType<typeof creature1>;
// type species1 = Human
type species2 = creatureType<typeof creature2>;
// type species2 = Animal
剔除方法的使用
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
// {}[keyof T] 是获取对象值的类型,never就不显示代表剔除方法,其他的就是值的类型。
type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
// 调用pick方法,第一个参数是对象,第二个参数是类型。
// 获取对象中不是方法的属性
class UserService {
id: number = 1;
name: string = "John";
save(): void {}
delete(): void {}
}
type remain = NonFunctionPropertyNames<UserService>;
// type remain = "id" | "name"
type UserData = NonFunctionProperties<UserService>;
// UserData is: { id: number; name: string }
// 方法被自动过滤掉了!
类的定义(UserService) 既是值(类的构造函数),也是类型(类的实例结构),因此泛型中的 T 可以直接传入类(UserService)
在类型工具的上下文中(如 type 定义、泛型约束),类名默认指其类型。 如果你想引用类的构造函数类型,需要显式使用 typeof UserService。
is 关键字实现类型守卫
缩小类型范围
//类型定义
type admin = {
name: string;
age: number;
token: "admin";
};
type normal = {
name: string;
age: number;
id: "normal";
};
// 使用示例
const user: any = {
name: "123",
age: 123,
id: "normal",
};
// 类型守卫
function isAdmin(user: admin | normal): user is admin {
return "token" in user;
}
//它的作用是告诉编译器:“当这个函数返回 true 时,传入的参数类型是我指定的类型”。
//使用
if (isAdmin(user)) {
// 缩小了user类型范围
user;
// const user: admin
console.log(user.token);
}
在 TypeScript 中,is 关键字是类型守卫的核心语法,它的作用是:
- 在运行时检查值的类型。
- 在编译时为 TypeScript 提供类型信息,从而实现类型安全。
通过 is,可以编写更精确、更安全的类型检查逻辑,让 TypeScript 编译器理解并应用类型缩小。
infer 推断
窥探类型内部结构
// 函数返回值推断
type myReturn<T> = T extends () => infer R ? R : never;
type exampleReturn = myReturn<() => Promise<string>>;
// type exampleReturn = Promise<string>
多个变量推断
type functioninfer<T> = T extens (first: infer A,second: infer B) => infer R ? {
args: [A ,B],
return: R
} : never
提取数组元素
type ArrayEle<T> = T extends (infer R)[] ? R : never;
Enum 枚举
在 TypeScript 中,enum(枚举)既可以作为值使用(在运行时有效),也可以作为类型使用(在编译时进行类型检查),这使得枚举在很多场景下都非常方便。
- 用作值
enum Status {
Pending = 0,
Success = 1,
Error = 2,
}
// 作为值使用
const currentStatus = Status.Success; // 赋值(值为 1)
console.log(currentStatus); // 运行时输出:1
// 作为函数参数
function handleStatus(status: Status) {
// ...
}
handleStatus(Status.Pending); // 传递枚举值(合法)
- 用作类型
- 值到类型转换
- 值作为属性名
enum obk {
name = "名字",
age = 123,
token = "admin",
}
type exp = {
[obk.name]: string;
};
// type exp = {
// "名字": string;
// }
const lss: exp = {
名字: "xxx",
};
类型工具
代码美化 / 简化
type Pretty<T, K extends keyof T> = {
[P in K]: T[P]
}
/**
* 美化输出,提高开发效率
* type A = { a: string };
* type B = { b: string };
* type C = A & B;
* // 编译器显示
* type C = A & B;
* // 美化后显示
* type PrettyC = Pretty<A & B>;
* // type PrettyC = {
* // a: string;
* // b: string;
* // }
*/
必选属性
type WithRequired<T, K extends keyof T> = T & {
[P in K]-?: T[P];
};
/**
*
* type exam = {
* ls?: number;
* arrive?: number;
* name: string;
* }
* type WithRequired<T, K extends keyof T> = T & {
* [P in K]-?: T[P];
* };
* type mid2 = WithRequired<exp, "ls" | "arrive">;
* // type mid2 = exp & {
* // ls: number;
* // arrive: number;
* // }
* 可配合Pretty使用,美化输出
*/