断言
断言的作用, 官方的解释
- 将联合类型断言为其中一种类型
- 父类断言为更加具体的子类
- any 断言为具体的类型
更通俗的解释: 类型断言更像是类型的选择, 而不是类型的转换
在实际中, 使用最多的就是在组件中设置了具体的联合类型值, 而在实际使用的时候, 类型推断和组件的类型定义不匹配, 需要手动 断言 一下它的格式
// 报错, 因为val不一定具有length属性
function func(val: string | number) :number {
if (val.length) {
return val.length
} else {
return val.toString().length
}
}
// 正确的写法
function func(val: string | number) :number {
if ((val as string).length ) {
return (val as string).length
} else {
return val.toString().length
}
}
更符合场景的一个例子
// antd 中的 Table 组件, columns 有一个属性叫做 align, 为AlignType类型, 如果Table经过封装, 传给 align的值可能会被类型推断为string, ts会报错 不能把 string赋值给AlignType, 此时就需要用到断言
interface & type
相同点
- 都可以描述对象或者函数
// interface
interface User {
name: string;
age: number;
}
interface UpdateUser {
(name: string, age: number): void;
}
// type
type User = {
name: string;
age: number;
}
type UpdateUser = (name: string, age: number): void;
- 都支持扩展
// interface
interface User {
name: string;
age: number;
}
interface Student extends User {
grade: number;
score: number;
}
// type
type User = {
name: string;
age: number;
}
type Student = User & {
grade: number;
score: number;
}
不同点
- interface 支持声明合并
interface User {
name: string;
}
interface User {
age: number;
}
// 这里的 User 同时有 name 和 age 两种
const user: User = {
name: '张三',
age: '18',
}
- type 可以声明基本类型别名、联合类型、元组类型等
// 联合类型
type User1 = {
name: string;
age: number;
}
type User2 = {
name: string;
score: number;
}
type Person = User1 | User2;
// 具体定义数组每个位置的类型
type PersonList = [User1, User2];
type size = 'small' | 'middle' | 'large';
- type 可以使用 typeof 获取实例的类型
const defaultProps = {
name: '张三',
age: 18,
score: 722,
}
type IProps = typeof defaultProps & {
favorite: [string];
}
const UserComponent: React.FC<IProps> = (props) => {
const { name, age, score, favorite } = props;
return (
<>
<p>{name}</p>
<p>{age}</p>
<p>{score}</p>
<p>{favorite.join('、')}</p>
</>
)
}
UserComponent.defaultProps = defaultProps;
总结
- 官方推荐使用 interface,除非你需要使用到 interface 无法满足,只能使用 type 时再使用 type 来定义类型
- 实践中, 除了基本类型的定义, 还需使用到联合类型, 交叉类型等, 更推荐使用 type 类型
typeof keyof
keyof 用于遍历某种类型的属性, 假设有一个类型 T, keyof T 将会给你一个新类型, 这个新类型就是 T 的属性组成的联合类型
typeof 操作符用于获取变量的类型
// 报错 type ‘string’ can’t be used to index type ‘{}’.
function getProp(obj: object, key: string) {
return obj[key];
}
// 限制 key 为 obj 的属性值
function getProp<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
另一个例子
enum ColorsEnum {
white = '#ffffff',
black = '#000000',
}
type Colors = keyof typeof ColorsEnum;
// 等价于
type Colors = "white" | "black"
// 首先 typeof ColorsEnum 会返回 ColorsEnum的类型, 类似于{ name: string, power: string }, keyof操作这个返回值, 得到其中的属性, 即white 和 black
声明文件
声明文件就是以 .d.ts 结尾的文件。常用于对第三方库或者项目中的一些公共类型的声明, 和声明文件紧密关联的是声明语句 declare
声明文件有全局的类型声明和局部的类型声明两种
.d.ts 里面,没有使用 import、export,默认是全局的。全局的类型声明在项目的任何地方都可以直接使用,无需引入。但是要特别注意类型命名冲突。在 .d.ts 文件中,只要有一个类型定义使用了 export,那这个声明文件就会变成模块化的。想要使用里面的类型定义,需要先通过 import 的方式将其引入才行。
总结:
-
全局的类型:直接放在最外层的 global.d.ts 或者 typing.d.ts 中,不使用 export 导出。
-
模块级的类型。在每个功能模块下,定义一个 index.d.ts 文件。在这个文件中写需要复用的类型定义。再通过 export 的方式将其导出。在需要使用类型的地方,再通过 import 导入使用。
泛型
泛型是对类型的编程
你不知道的 TypeScript 泛型(万字长文,建议收藏)
常见工具类型
Partial, Record<Keys,Type>, Pick<Type, Keys>, Omit<Type, Keys>
Partial作用: 将传入的类型定义转换成全部可选的值
type User = {
id: number;
name: string;
}
type UserPartial = Partial<User>;
// 等价于
type UserPartial = {
id?: number | undefined;
name?: string | undefined;
}
Required作用: 将传入的类型定义全部转换在必选的
Record<Keys,Type>作用: 构建一个对象类型,其属性键是 Keys,其属性值是 Type
interface CatInfo {
age: number;
breed: string;
}
type CatName = "miffy" | "boris" | "mordred";
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "Persian" },
boris: { age: 5, breed: "Maine Coon" },
mordred: { age: 16, breed: "British Shorthair" },
};
Pick<Type, Keys>作用: 通过从 Type 中选择一组属性 Keys(字符串文字或字符串文字的联合)来构造一个类型。
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
Omit<Type, Keys>作用: 排除一个类型下的一个或者几个类型
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
type TodoInfo = Omit<Todo, "completed" | "createdAt">;
const todoInfo: TodoInfo = {
title: "Pick up kids",
description: "Kindergarten closes at 5pm",
};
参考
TypeScript - 简单易懂的 keyof typeof 分析 TS 中的 keyof 和 typeof 操作符 你不知道的 TypeScript 泛型(万字长文,建议收藏)