这是我们今天要聊的内容,老样的,如果你已经可以轻松看懂,欢迎直接左转去看同事 Kyle 的精彩文章 — 「今晚,我想来点 Web 前端效能优化大补帖!」。
在 Day14 我们理解了如何透过 Mapped Type 修改物件型别中属性的 value,在 Day15 中我们则理解了如何透过 Mapped Type 来修改物件型别中属性的 key,看起来好像已经能完整操作物件型别了,但等等,在 TypeScript 的物件型别中还有一个是 Property Modifiers(属性修饰符)。
属性修饰符(Property Modifiers)这个词你可能没听过,但应该一定用过,像是透过在属性名称後面加上 ?
让该属性变成是 optional 的,或是透过 readonly
让该属性在 type-checking 时不能被修改,另外像是 Day14 提过的 Index Signatures 也算是 Property Modifiers 的一种:
// Property Modifiers: ?, readonly
interface Person {
firstName: string;
lastName?: string; // lastName is optional
readonly age: number; // you should not mutate the age
}
在知道 Property Modifiers 後,让我们来看看如何透过 Mapped Types 来修改属性的 Property Modifiers。
如果要在 Mapped Types 中添加或移除 Property Modifiers 的话(像是把所有的属性都变成 optional),需要用到 +
或 -
,预设没写的话就是 +
,来看下面几个例子。
要改变物件属性是否为 optional,只需要使用 +?
或 -?
即可。若要把每个物件型别的属型都变 optional,可以使用 +?
或 ?
都可以,因为预设就会是 +
:
相反的如果要让物件型别全部的属性都不是 optional 的话,可以用 -?
,但这里的减号就不能省略:
实际上使用这两个 Type Utility 的话,效果会像是这样:
interface Person {
firstName: string;
lastName?: string; // lastName is optional
readonly age: number; // you should not mutate the age
}
// 把每个物件型别的属性都变成 optional
type ToOptionalProperty<T> = {
[K in keyof T]+?: T[K];
};
// 把每个物件型别的属性的 optional 都移除
type RemoveOptionalProperty<T> = {
[K in keyof T]-?: T[K];
};
type PersonWithOptionalProps = ToOptionalProperty<Person>;
type PersonWithoutOptionalProps = RemoveOptionalProperty<Person>;
一开始 Person
中并不是每个 Property 都是 optional 的,但经过 ToOptionalProperty
,所有 Properties 就都会是 Optional 的:
而 RemoveOptionalProperty
则能够以此类推,使用 -?
後所有物件属性原本的 optional 也都会被移除。
使用 Mapped Modifiers 添加或移除 readonly
属性的方式也完全一样,也是透过 +
和 -
:
// 把每个物件型别的属性都加上 readonly
type ToReadOnlyProperty<T> = {
+readonly [K in keyof T]: T[K]; // 最前面的 + 可以省略
};
// 把每个物件型别的属性都移除 readonly
type RemoveReadOnlyProperty<T> = {
-readonly [K in keyof T]: T[K];
};
type PersonWithReadonlyProps = ToReadonlyProperty<Person>;
type PersonWithoutReadonlyProps = RemoveReadonlyProperty<Person>;
使用起来的效果就和 optional 时的说明一样,如果针对 Person
使用了 RemoveReadonlyProperty
的话,原本的 readonly
modifier 会被移除:
实际上根据笔者个人经验,比较少直接用的 Mapped Modifiers 来操作,不是它们不常被用到,而是因为 TypeScript 已经把它们包成几个常用的 Utility Types,像是 Partial<Type>
、Required<Type>
或 Readonly<Type>
,这三个 Type Utilities 都是在 Mapped Types 中使用 Mapped Modifiers 来做的操作,未来会再看到更多 Mapped Types 的延伸变化,就能理解 Mapped Type 有多强大。
有了 Mapped Modifiers 的概念後,这几个 Utility Types 的原始码都会很好理解。其中最常用的 Partial<Type>
其原始码是:
// Make all properties in T optional
type Partial<T> = {
[P in keyof T]?: T[P];
};
跟我们刚刚写的 ToOptionalProperty
是不是一模一样呢?
然後是 Required<Type>
的原始码:
// Make all properties in T required
type Required<T> = {
[P in keyof T]-?: T[P];
};
是不是也和刚刚写的 RemoveOptionalProperty
一样?
最後是 Readonly<Type>
的原始码:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
也和刚刚我们提到的 ToReadOnlyProperty
相同。
https://tsplay.dev/WK86ow @ TypeScript Playground
万事起头难 爬山一开始总会比较喘、比较累 但逐渐靠近山头後 身体就慢慢适应环境了 登山者也较能欣赏...
前言 接着昨天分享的话题,针对成为 Scrum Master 的经历与想法再进行补充。 大家从标题「...
我想先回来介绍一些深度学习框架好了, 非类神经的演算法也可以被归为AI, 但是神经网路的深度学习算是...
前言 其实你知道吗? 今天要讲的 this.state this.setState 其实就是之前介绍...
标题那个还真的是没有写错~ 且听我细细道来~ ------------------------ 【一...