TS 中内置了一个叫做 Partial
的类型,它的作用是把一个类型中的成员设置为可选。例如:
type Todo = {
title: string;
description: string;
};
Todo
中有两个成员,分别是 title
和 description
,如果把这个类型赋值给 params
,那么 params
必须包含 title
和 description
这两个成员。
const params: Todo = {
title: "title",
description: "description",
};
如果我们需要让 Todo
中的成员变成可选,可以使用 Partial 进行转换。
const params: Partial<Todo> = {
description: "desc",
};
这个用法,我一般用于对象合并,例如:
type Todo = {
title: string;
description: string;
};
const updateTodo = (todo: Todo, fieldsToUpdate: Partial<Todo>) => {
return { ...todo, ...fieldsToUpdate };
};
const todo1: Todo = {
title: "title",
description: "description",
};
const todo2 = updateTodo(todo1, {
description: "desc",
});
如果,我们现在在 Todo
类型中,添加一个 states
的成员,它是一个对象。如果想把 states
中的属性也变为可选的,那么 Partial
就无法做到了。
可以从上面的图中发现,Partial
只是把 states
变成了可选,但是,没有把 states
中的属性变成可选。我们可以自己写一个简单 DeepPartial
类型来解决这个问题。
在写之前,先来看看 Partial
在 TS 内部是如何实现的。
/**
* Make all properties in T optional
*/
type Partial<T> = {
[P in keyof T]?: T[P];
};
可以看到,Partial 内部通过遍历所有属性,将属性都设置成了可选。
实现思路是,判断属性值T[P]的类型是否是 object,如果是,在进行一次遍历。
type MyDeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? MyDeepPartial<T[P]> : T[P];
}