不知不觉typescript的学习快两个月了,适当做一下整理。
开始
在刚开始学习typescript时候,挥斥方遒地敲了好多字!给自己罗列了几个研究目标:
-
类型系统
- typescript带来的类型系统包含哪些内容,哪些是在原有基础做的加法,哪些是新增的概念,哪些,比如 interface、enum、unions等;
- 这些类型系统有哪些实践,是如何帮助我们提高代码的健壮性和可预计性(类型系统的作用)
-
工具
- typescript和编辑器的集成(比如vscode),带给了我们编程体验上的提升,比如更好的文档说明、提示、自动纠正等,这些工具的体验是怎么样的,如何更好地使用这些工具
- playground、DefinitelyTyped是什么
-
在ts官网首页有这样一句话:
When new features have reached stage 3, then they are ready for inclusion in TypeScript.
ts致力于和标准一块发展,提供对新特性更好的支持,比如 Optional Chaining、Nullish coalescing Operator等ES2020特性,探索挖掘有哪些特性是那么不为人知,又却是可以给开发带来帮助的
-
社区
- typescript和eslint的合作,lint typescript代码是用eslint还是tslint
- typescript和babel的合作,babel是一个compiler,typescript也有这方面的职能,双方有冲突。typescript有寻求babel合作,把compiler的职责专门交给babel,现在落地如何?
- typescript有哪些社区,stackoverflow、discord等
-
日常体验
- 在日常开发中,next+react+ts下的ts体验如何,踩过什么坑
- 体验的一般流程如何,用到的比较多的是什么
- tsconfig等配置
-
更多
- vue3.0对typescript的支持到什么程度了
- typescript背后AST转换等等
- typescript和几个竞争对手flow、purescript等对比
怀揣着这张意气风发的Map,开始了!
学习
类型系统
说白了,typescript就是提供了一层类型系统,始发站自然而然地选择了这里。
自诩英语很好的我刚开始嚼起了官方英文文档 ,嚼得我头皮发麻,一个是内容过于详细,没有项目实践很快就忘记了,另一个是文档缺乏组织性,还有一些晦涩的章节对新手不太友好,比如 namespaces 、Namespaces and Modules 。(现在改版后的The TypeScript Handbook比老版要好很多)
于是临时改变了策略,从 playground-exmaple 打起,有基本认识后,有需要再去详细文档查看!
整个类型系统可以分为两部分:提升JavaScript体验( improves working with JavaScript)、扩展JavaScript安全性和工具(extends JavaScript to add more safety and tooling)。做了简单的梳理:

这里碰到了的一些概念,在一开始不太好接受。
比如 TypeScript 的类型系统被称为结构类型系统,也就是官方文档的这段描述:
One of TypeScript’s core principles is that type checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural subtyping”.
看下面的demo:champion 函数需要的参数类型是Team,而传入的是DetailedTeam,这是允许的,因为ts的结构类型系统仅比较DetailedTeam是否包含Team的结构
interface Team {
name: string
city: string
}
interface DetailedTeam {
name: string
city: string
mascot: string
}
function champion(team: Team) {
const { name, city } = team
console.log(`The ${name} from ${city} won the NBA 2020 championship!`)
}
let teamA: DetailedTeam = {
name: 'Rockets',
city: 'Houston',
mascot: 'bear'
}
champion(teamA)
有一个例外是当赋值操作的是函数,看下面的demo:是允许入参少的 createBall函数复制给 createSphere 函数
let createBall = (diameter: number) => ({ diameter });
let createSphere = (diameter: number, useInches: boolean) => {
return { diameter: useInches ? diameter * 0.39 : diameter };
};
createSphere = createBall; //👌
createBall = createSphere; //Type '(diameter: number, useInches: boolean) => { diameter: number; }' is not assignable to type '(diameter: number) => { diameter: number; }'
再比如比较有热度的话题: interface 和 type alias(类型别名)的区别。
在typescript中,interface和type都可以来表达对象结构、函数。它们也都支持扩展,interface可以继承interface,也可以继承type,反过来type也一样。当然写法不一样:
Typescript doc example: Types vs Interfaces
那差别在哪里:
-
type alias除了表达对象、函数外,还支持表达其他类型,比如 unions、tuples、primitives,这个能力interface不具备
// primitive type Name = string; // object type PartialPointX = { x: number; }; type PartialPointY = { y: number; }; // union type PartialPoint = PartialPointX | PartialPointY; // tuple type Data = [number, string]; -
interface允许定义多次,结果取交集,而type alias这样做会报错
// These two declarations become: // interface Point { x: number; y: number; } interface Point { x: number; } interface Point { y: number; } const point: Point = { x: 1, y: 2 }; -
type alias内支持
in操作,而 interface 不支持//demo1 type Partial<T> = { [P in keyof T]?: T[P]; }; //demo2 type Keys = "firstname" | "surname" type DudeType = { [key in Keys]: string } interface DudeInterface { [key in Keys]: string } const test: DudeType = { firstname: "Pawel", surname: "Grzybek" }
其他再比如 unknown 和 any 的区别(这篇文章讲的很好:mariusschulz: the-unknown-type-in-typescript )、Type Widening 和 Narrowing的各个招数等等,这里不细节展开了。
以后忘记了,策略可以是:个人整理资料 => Playground Example => 官方文档
ES2020
typescript是使用JavaScript新特性很好的土壤,于是调研了一下ES2020。
这在另一篇文章中有详细说明,移步:Hello ES2020 & ES2019!。
用到比较多的是可选链(Optional chaining)、空值合并运算符(Nullish coalescing operator)。
工具
vscode对TypeScript支持
毕竟是微软一家人,支持力度是相当可以的,详细说明在这里:TypeScript in Visual Studio Code。
耳熟能详的有 智能感知(IntelliSense)、悬浮可查看详细说明(Hover information),再提两个日常开发常用的:
-
code navigation:
F12: 在新页面,查看选中内容的源码定义Alt/Opt + F12:在当前页内嵌窗口,查看选中内容的源码定义shift + F12:在当前页内嵌窗口,查看选中内容的引用win/command+F12:查看interface应用/实例
-
organize imports: 整理import语句顺序、移除没有使用的
-
快捷键:
shift+Opt/Alt+o -
如果需要保存时起作用,配置:
{ "editor.codeActionsOnSave": { "source.organizeImports": true } }
-
这里额外提一下插件:JavaScript and TypeScript Nightly ,使用 typescript@next 作为vscode 内置ts版本,享用最新最丝滑的ts编程体验。
playground
playground就不说了,之前看Youtube上一个演讲视频 Anders Hejlsberg 提到他们团队专门有一人来做playground这个项目。
社区
Definitely Typed
刚开始的时候把DT放在了工具,了解过后更觉得应该放在社区。
我们知道虽然 TypeScript 势头很猛,但很多第三方主流的库还是JavaScript编写的,这样怎么使它也享用vscode的体验提升呢(或者说,在typescript项目中使用)?答案是写声明文件,就是经常看到的.d.ts后缀。
声明文件有了之后,如何让它们起作用,即如何发布呢,有两种方式:
- 和npm包捆绑在一起(内置类型定义文件),比如Vue的types文件夹
- 提交到DefinitelyTyped,由它发布到@types organization,通过 npm i @types/xxxx 安装,这样其他人也可以对JavaScript库做贡献
所以 DefinitelyTyped 就是这样一个社区,把常用模块声明文件提交,它会发布到@types organization,它就成了这样的一个集合。
TypeScript与ESLint
TSLint已经退出Lint TypeScript舞台:
:warning: TSLint has been deprecated as of 2019. Please see this issue for more details: Roadmap: TSLint → ESLint. typescript-eslint is now your best option for linting TypeScript.
这篇文章很清晰地介绍了在TypeScript+React项目中使用ESLint和Prettier标准化代码要做的所有事情:Using ESLint and Prettier in a TypeScript Project。
如果使用到了hooks,需要增加hooks的lint规则:eslint-plugin-react-hooks
复盘
回到最初设定的目标(简单调整了一下),做一下复盘:
- 类型系统
- 工具
- vscode支持
- playground
- javascript语言新特性
- 社区
- typescript与ESLint
- typescript与babel
- Definitely Typed
- stackoverflow、discord等论坛
- 更多
- vue3.0对typescript的支持、体验
- typescript背后AST转换等等
- typescript和几个竞争对手flow、purescript等对比
NEXT
接下来关于typescript的研究/学习话题还有很多,罗列一下第二张Map。
- 更落地
- React TypeScript Cheatsheet :React场景,有些关于class components的可以忽略;
- 更深入
- TypeScript Deep Dive: 在很多地方有推荐,粗略看过一下,包罗万象
- Learn how to contribute to the TypeScript compiler on GitHub through a real-world example :typescript编译器、AST相关
- 更广度
- typescript背后AST转换等等
- typescript和几个竞争对手flow、purescript等对比
- 其他
- typescript与babel
- stackoverflow、discord等论坛,关注typescript新动态
小结
在学习之初,这篇文章 TypeScript-一种思维方式 清晰明确的观点给了我很多启发 ,在后面的学习过程也更加感同身受。
主要有3点:
-
学习一项新的技能,清楚其边界很重要,相关的细节知识则可以在后续的使用过程中逐步的了解。我们都知道,TS 是 JS 的超集,所以学习 TS 的第一件事情就是要找到「超」的边界在哪里
从语言本身而言,TS的边界在引入了一套类型系统。TS相关工具的助力,使得编程体验更加丝滑;
-
思维方式改变-明确的模块抽象过程:在开始一个模块码代码之前,会自然而然考虑输入值和返回值,做抽象和拓展;
-
思维方式改变-更自信的写前端代码:TS会捕捉容易被忽略的情况,也许这就是一个bug
另外推荐两个链接:
- Marius Schulz-typescript evolution :这位博主文章详细且易懂
- Typescript-FAQ:github wiki 整理的常见问题解答