}
interface TopNavState {
userId: string;
pageTitle: string;
recentFiles: string[];
}
上述的 TopNavState 接口相比 State 接口只是缺少了 pageContents
属性,但我们却重复声明其他三个相同的属性。为了减少重复代码,我们可以这样做:
type TopNavState = {
userId: State[‘userId’];
pageTitle: State[‘pageTitle’];
recentFiles: State[‘recentFiles’];
};
在上面代码中,我们通过成员访问的语法来提取对象中属性的类型,从而避免重复定义接口中相关属性的类型。但这并没有解决本质的问题,我们还有很大的优化空间。针对这个问题,我们可以利用映射类型来进一步做优化:
type TopNavState = {
};
鼠标悬停在 TopNavState 显示它的声明,实际上,这个定义与前一个定义完全相同。
通过映射类型优化后的代码,相比 TopNavState 接口最初的代码简洁了许多。那还有没有优化空间呢?其实是有的,我们可以利用 TypeScript 团队为我们开发者提供的工具类型,这里我们可以使用 Pick
:
type TopNavState = Pick<
State, ‘userId’ | ‘pageTitle’ | ‘recentFiles’
;
其实除了 Pick
之外,在实际开发过程我们还可以利用其他内置的工具类型来减少重复代码。这里我们再来介绍另一个比较常用的工具类型,即 Partial
。以下是未使用 Partial
的例子:
interface Options {
width: number;
height: number;
color: string;
label: string;
}
interface OptionsUpdate {
width?: number;
height?: number;
color?: string;
label?: string;
}
class UIWidget {
constructor(init: Options) {
/* … */
}
update(options: OptionsUpdate) {
/* … */
}
}
在以上示例中,我们定义了 Options 和 OptionsUpdate 两个接口,它们分别用于描述 UIWidget 的初始化配置项和更新配置项。相比初始化配置项,更新配置项的所有属性都是可选的。
现在我们来开始优化上述的代码,我们先来看一下不使用 Partial
的情形:
type OptionsUpdate = {[k in keyof Options]?: Options[k]};
keyof 操作符接受一个类型,并返回一个由 key 组成的联合类型:
type OptionsKeys = keyof Options;
// Type is “width” | “height” | “color” | “label”
而 in
操作符是用来遍历枚举类型或联合类型。接着,我们来看一下使用 Partial
的情形:
class UIWidget {
constructor(init: Options) { /* … */ }
update(options: Partial) { /* … */ }
}
其实 Partial
并没有什么神奇的地方,我们来看一下它的定义:
// node_modules/typescript/lib/lib.es5.d.ts
/**
* Make all properties in T optional
*/
type Partial = {
[P in keyof T]?: T[P];
};
在以上代码中,首先通过 keyof T
拿到 T
的所有属性名,然后使用 in
进行遍历,将值赋给 P
,最后通过 T[P]
取得相应的属性类型。中间的 ?
号,用于将所有属性变为可选。
有时候,你可能还会发现自己想要定义一个类型来匹配一个初始配置项的形状,比如:
const INIT_OPTIONS = {
width: 640,
height: 480,
color: “#00FF00”,
label: “VGA”,
};
interface Options {
width: number;
height: number;
color: string;
label: string;
}
对于 Options 接口来说,我们还可以使用 typeof 操作符来快速定义该接口类型:
type Options = typeof INIT_OPTIONS;
此外,在使用可辨识联合(代数数据类型或标签联合类型)的过程中,也可能出现重复代码。比如:
interface SaveAction {
type: ‘save’;
// …
}
interface LoadAction {
type: ‘load’;
// …
}
type Action = SaveAction | LoadAction;
type ActionType = ‘save’ | ‘load’; // Repeated types!
为了避免重复定义 'save'
和 'load'
,我们可以使用前面提到的成员访问语法,来提取对象中属性的类型:
type ActionType = Action[‘type’]; // 类型是 “save” | “load”
这里需要注意的是,Action['type']
返回的是联合类型,而如果我们使用前面介绍的 Pick
工具类型,它会返回一个含有 type 属性的接口:
type ActionRec = Pick<Action, ‘type’>; // {type: “save” | “load”}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
总结一下这三次面试下来我的经验是:
-
一定不要死记硬背,要理解原理,否则面试官一深入就会露馅!
-
代码能力一定要注重,尤其是很多原理性的代码(之前两次让我写过Node中间件,Promise.all,双向绑定原理,被虐的怀疑人生)!
-
尽量从面试官的问题中表现自己知识的深度与广度,让面试官发现你的闪光点!
-
多刷面经!
我把所有遇到的面试题都做了一个整理,并且阅读了很多大牛的博客之后写了解析,免费分享给大家,算是一个感恩回馈吧,有需要的朋友【点击我】免费获取。祝大家早日拿到自己心怡的工作!
篇幅有限,仅展示部分内容
了很多大牛的博客之后写了解析,免费分享给大家,算是一个感恩回馈吧,有需要的朋友【点击我】免费获取。祝大家早日拿到自己心怡的工作!**
篇幅有限,仅展示部分内容