我个人在7月份的笔记,不定期更新
一、typescript - 找不到参数类型为“字符串”的索引签名
个人习惯用策略模式去优化多个if/switch case的代码,
getTitle(name: any) {
const mapping={
ApproveList: '签署审批',
signRecord: '签署记录',
}
return mapping[name]
}
但在ts下你可能会得到以下报错:
const mapping: {
ApproveList: '签署审批',
signRecord: '签署记录',
}
Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{ ApproveList: string; signRecord: string; }'.ts(7053)
原因是ts并不知道你传入的string索引,是否在对象中有对应的成员属性
知道问题了,我们就可以对应的解决方法:
- 声明一个类型。限制构成对象属性的字符串
- 以这个类型作为key,生成策略匹配的对象
- 以这个type类型作为函数参数
type RouteNames = 'ApproveList' | 'signRecord'
getTitle(name: RouteNames) {
const mapping: Record<RouteNames, string> = {
ApproveList: '签署审批',
signRecord: '签署记录',
}
return mapping[name]
}
this.title = this.getTitle(routeName as RouteNames) || ''
二、如何选择第三方 NPM 包?
- 检查开源许可证
- 看贡献频率和下载量
- 权衡包体积大小
- 是否有大型开发团队在进行维护
- 评估安全性
检查开源许可证(License)
开源许可证是一种法律许可。通过它,版权拥有人明确允许,用户可以免费地使用、修改、共享版权软件。
版权法默认禁止共享,也就是说,没有许可证的软件,就等同于保留版权,虽然开源了,用户只能看看源码,不能用,一用就会侵犯版权。所以软件开源的话,必须明确地授予用户开源许可证。
License 通常分两大类:”CopyLeft(著佐权)” 和 “Permissive(宽松式)”:
CopyLeft:如果你使用了这个包,那么你的代码也必须开源。这对一些商业化的项目不太友好,比如 GPL 和 LGPL 协议。
Permissive:对包做了最低限度的使用限制,允许闭源,可以说几乎没有限制,但是各自又有一些区别,具体见下图。
评估安全性
包安全性是选择 NPM 包的另一个关键因素,在仓库的「Security」tab 下可以看到它的安全策略。
如果维护者已经采取了措施来确保安全性,会显示已激活。
对于项目中已有的 NPM 依赖,可以使用命令 npm audit 来进行安全性检查。
参考链接:
三、统一前端项目的 Node 版本和包管理器
锁定项目 Node 版本
通过在 package.json 中指定 engines 字段,可限定项目使用的 node 版本。 下面配置仅允许用户使用 14 或者 16的版本。更多的配置可以参考 package.json 、npm Docs 、semver
// package.json
"engines": {
"node": "14.x || 16.x"
},
配置之后你会发现,该字段只对 yarn 生效。那如何对 npm 也生效呢?在项目根目录下的 .npmrc 文件中增加如下配置
// .npmrc
engine-strict = true,
以上配置完成后,npm install 试试吧,错误的 Node.js 将直接退出
锁定包管理器
利用 only-allow 工具包、npm scripts 快速实现锁定。
步骤一:在项目中 npm install -D only-allow
步骤二:在 package.json 文件中进行配置 scripts.preinstall , 允许输入的值 only-allow npm、only-allow pnpm、only-allow yarn
// package.json
"scripts": {
"preinstall": "only-allow npm",
...
}
以上配置完成后,可以再乱用 (yarn、npm、pnpm) 试试
四、JSX中要注意的一些写法
.sync语法糖如何书写?
// template的sync语法糖:
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
<span>内容</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmUnbind">确 定</el-button>
</span>
</el-dialog>
// template非语法糖
<el-dialog title="提示" :visible="dialogVisible" @update:visible = "val => this.dialogVisible = val" width="30%">
// JSX 这么写
<el-dialog title="提示" visible={this.dialogVisible} {...{on:{'update:visible': val => this.dialogVisible = val}}} width="30%">
<span>内容</span>
<span slot="footer" class="dialog-footer">
<el-button onClick={()=>...}>取 消</el-button>
<el-button type="primary" onClick={xxx函数名}>确 定</el-button>
</span>
</el-dialog>
v-bind=”$attrs” 如何书写?
<el-cascader
ref="guiCascader"
v-model={this.formData[item.key]}
key={item.id}
placeholder={item.placeholder || "请选择"}
options={item.options}
show-all-levels={item.showAllLevels || true}
clearable={item.clearable || false}
collapse-tags={item.collapseTags}
{...{
props: {
...this.$attrs,
props: item.props
}
}}
/>
五、讲清楚同源、跨源、同站、跨站、Cookie 的 SameSite 属性
5.1源
“源”是scheme(也被称为协议,例如HTTP和HTTPS),主机域名和端口(如果有指定)的结合。例如,给定一个URLhttps://www.example.com:443/foo,它的“源”是https://www.example.com:443。
一条请求的核心部分就是这三部分:scheme+主机域名+端口,三者能够唯一标识通信方,这三部分的组成也被称为套接字(socket)。
⚡️ 下文scheme统统指例如HTTP或者HTTPS这样的协议。
5.2同源和跨源
相同scheme、主机域名和端口结合的网站被认为是“同源”,其他的被认为是“跨源”。
5.3站(Site)
站(site)= eTLD+1
TLD 表示顶级域名,例如 .com、.org、.cn 等等,不过顶级域名并不是一成不变的,会随着时间推移增加。
TLD+1 表示顶级域名和它前面二级域名的组合,例如网址是:
https://www.example.com:443/foo
那么:
TLD 是 .com TLD+1 是 example.com
但是,这种表示方式是有缺陷的,例如对于下面的网址:
https://www.example.com.cn
如果按照上面的规则,它的 TLD+1 就是 com.cn,并不能表示这个站点,真正能表示这个站点的应该是 example.com.cn 才对,所以衍生出 eTLD 的概念,即有效顶级域名:
eTLD:com.cn
eTLD+1:example.com.cn
eTLD 由 Mozilla 维护在公共后缀列表(Public Suffix List)中,而「站」的定义就是这里的 eTLD+1。
5.4同站和跨站
eTLD+1 完全一致。
假设现在有源A:https://www.example.com:443
大家同样可以遮住第2列,猜一猜源B和源A是属于同站还是跨站:
源B | 答案 |
---|---|
https://www.evil.com:443 | 跨站,部分域名不一样 |
https://login.example.com:443 | 同站,eTLD+1一样 |
http😕/www.example.com:443 | 同站,同上 |
https://www.example.com:**80 | 同站,同上 |
https://www.example.com:443 | 同站,同上 |
https://www.example.com | 同站,同上 |
5.5 Cookie 的 SameSite 属性
Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。
它可以设置三个值:
- Strict
- Lax
- None
Strict
Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。
Lax
没有 SameSite 属性的 Cookies 默认为 SameSite=Lax
Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。
设置了Strict或Lax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。
None
Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。 下面的设置无效。
Set-Cookie: widget_session=abc123; SameSite=None
下面的设置有效
Set-Cookie: widget_session=abc123; SameSite=None; Secure
5.6 如何检查一个请求是“同站”,“同源”,或者“跨站”
Chrome发送伴随Sec-Fetch-SiteHTTP请求头的请求。其他浏览器截至2020年4月还没有支持Sec-Fetch-Site。这是获取元数据请求头 提案更广的一部分。这个头部会有一个如下其中之一的值:
- cross-site
- same-site
- same-origin
- none
5.7 和浏览器的“禁用第三方 cookie”功能有什么区别?
主流浏览器都有禁用第三方 cookie 的功能,它和 SameSite 有什么区别?我能总结 2 点:
-
该功能是由用户决定是否开启的,是针对整个浏览器中所有 cookie 的,即便有些浏览器可以设置域名白名单,那最小单位也是域名;而 SameSite 是由网站决定是否开启的,它针对的是某个网站下的单个 cookie。
-
该功能同时禁用第三方 cookie 的读和写,比如 a.com 发起了对 b.com 的请求,这个请求完全不会有 Cookie 请求头,同时假如这个请求的响应头里有 Set-Cookie: foo=1,foo 这个 cookie 也不会被写进浏览器里;而 SameSite 只禁用读,比如 b.com 在用户浏览器下已经写入了个 SameSite cookie foo,当 a.com 请求 b.com 时,foo 肯定不会被发送过去,但 b.com 在这个请求的响应里又返回了: Set-Cookie: bar=1; SameSite=Strcit,这个 bar 会成功写入浏览器的 cookie 里。
5.8 怎样才算第三方请求?
当一个请求本身的 URL 和它的发起页面的 URL 不属于同一个站点时,这个请求就算第三方请求。那么怎样算是同一个站点?是我们经常说的同源(same-origin)吗,cross-origin 的两个请求就不属于同一个站点?显然不是的,foo.a.com 和 bar.a.com 是不同源的,但很有可能是同一个站点的,a.com 和 a.com:8000 是不同源的,但它俩绝对是属于同一个站点的,浏览器在判断第三方请求时用的判断逻辑并不是同源策略,而是用了 Public Suffix List 来判断。
六、记住在单文件中禁用某项eslint的方法
/* eslint-disable @typescript-eslint/camelcase */