1. Why
在介绍什么叫 TypeScript 类型编程和为什么需要学习 TypeScript 类型编程之前,我们先看一个例子,这里例子里包含一个 promisify 的函数,这个函数用于将 NodeJS 中 callback style 的函数转换成 promise style 的函数。
import * as fs from "fs";
function promisify(fn) {
return function(...args) {
return new Promise((resolve, reject) => {
fn(...args, (err, data) => {
if(err) {
return reject(err);
}
resolve(data);
});
});
}
}
(async () => {
let file = await promisify(fs.readFile)("./xxx.json");
})();
如果我们直接套用上述的代码,那么 file 的类型和 promisify(fs.readFile)(...)
中 (...)
的类型也会丢失,也就是我们有两个目标:
我们需要知道
promisify(fs.readFile)(...)
这里能够接受的类型。我们需要知道
let file = await ...
这里 file 的类型。
这个问题的答案在实战演练环节会结合本文的内容给出答案,如果你觉得这个问题简单得很,那么恭喜你,你已经具备本文将要介绍的大部分知识点。如何让类似于 promisify这样的函数保留类型信息是“体操”或者我称之为类型编程的意义所在。
2. 前言 (Preface)
最近在国内的前端圈流行一个名词“TS 体操”,简称为“TC”,体操这个词是从 Haskell 社区来的,本意就是高难度动作,关于“体操”能够实现到底多高难度的动作,可以参照下面这篇文章。
3. 建模 (Modeling)
4. 语法分类 (Grammar Classification)
4.1 基本类型 (Basic Types)
4.2 函数 (Function)
TypeScript 函数的缺陷 (Defect)
高版本才能支持递归
函数不能作为参数
支持闭包,但是没有办法修改闭包中的值
4.3 语句 (Statements)
变量声明语句 (Variable Declaration)
4.4 表达式 (Expressions)
带三元运算符的条件表达式 (IfExpression with ternary operator)
函数调用/定义表达式 (CallExpression)
循环相关 (Loop Related)(Object.keys、Array.map等)
循环实现思路 (Details Explained )
对对象进行遍历 (Loop Object)
对数组(Tuple)进行遍历 (Loop Array/Tuple)
map
reduce
4.5 成员表达式 (Member Expression)
4.6 常见数据结构和操作 (Common Datastructures and Operations)
Set
Add
Remove
Has
Intersection
Diff
Symmetric Diff
ToIntersectionType
ToArray
Size
Map/Object
Merge/Object.assign
Intersection
Filter
Array
成员访问
Append
Pop
Dequeue
Prepend
Concat
Filter
Slice
4.7 运算符 (Operators)
基本原理 (Details Explained)
===
+
-
4.8 其他 (MISC)
inferface
Utility Types
5. 实战演练 (Excercise)
Promisify
答案
MyReturnType
Readonly 2
Type Lookup
Get Required
6. 想法 (Thoughts)
沉淀类型编程库 (Supplementary Utility Types)
https://github.com/piotrwitek/utility-types
https://github.com/sindresorhus/type-fest
直接用 JS 做类型编程 (Doing Type Computing in Plain TS)
7. Reference
[1] https://www.zhihu.com/question/418792736/answer/1448121319
[2] 有趣的 brain teaser: https://github.com/type-challenges/type-challenges
[3] AST(抽象语法树)的角度来看: https://github.com/babel/babel/blob/main/packages/babel-types/src/definitions/core.js
[4] Boolean: https://www.typescriptlang.org/docs/handbook/basic-types.html#boolean
[5] Number: https://www.typescriptlang.org/docs/handbook/basic-types.html#number
[6] String: https://www.typescriptlang.org/docs/handbook/basic-types.html#string
[7] Array: https://www.typescriptlang.org/docs/handbook/basic-types.html#array
[8] Tuple: https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple
[9] Enum: https://www.typescriptlang.org/docs/handbook/basic-types.html#enum
[10] Unknown: https://www.typescriptlang.org/docs/handbook/basic-types.html#unknown
[11] Any: https://www.typescriptlang.org/docs/handbook/basic-types.html#any
[12] Void: https://www.typescriptlang.org/docs/handbook/basic-types.html#void
[13] Null and Undefined: https://www.typescriptlang.org/docs/handbook/basic-types.html#null-and-undefined
[14] Never: https://www.typescriptlang.org/docs/handbook/basic-types.html#never
[15] Object: https://www.typescriptlang.org/docs/handbook/basic-types.html#object
[16] Declaration Merging: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
[17] 这个链接: https://www.typescriptlang.org/docs/handbook/utility-types.html
[18] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/util.promisify/implementation.d.ts
[19] https://github.com/type-challenges/type-challenges/blob/master/questions/2-medium-return-type/README.md
[20] https://github.com/type-challenges/type-challenges/blob/master/questions/8-medium-readonly-2/README.md
[21] https://github.com/type-challenges/type-challenges/blob/master/questions/62-medium-type-lookup/README.md
[22] https://github.com/type-challenges/type-challenges/blob/master/questions/57-hard-get-required/README.md
最后
如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:
本文分享自微信公众号 - 前端下午茶(qianduanxiawucha)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。