这是第 84 篇不掺水的原创,想获取更多原创好文,请搜索公众号关注咱们吧~ 本文首发于政采云前端博客: 编写高质量可维护的代码:Awesome TypeScript
高质量可维护的代码应具有可读性高、结构清晰、低耦合、易扩展等特色。而原生的 JavaScript 因为其弱类型和没有模块化的缺点,不利于大型应用的开发和维护,所以,TypeScript 也就应运而生。前端
TypeScript 是 JavaScript 的一个超集,它的设计初衷并非为了替代 JavaScript,而是基于 JavaScript 作了一系列的加强,包括增长了静态类型、接口、类、泛型、方法重载等等。因此,只要你有必定的 JavaScript 功底,那么 TypeScript 上手就很是简单。而且,你能够在 TypeScript 中愉快的使用 JavaScript 语法。typescript
接下去,本文将给你们分享下,TypeScript 的重要特性以及在实际场景中的使用技巧,帮助你们更高效的编写高质量可维护的代码。编程
JavaScriptjson
TypeScript数组
TypeScript 是静态类型语言,经过类型注解提供编译时的静态类型检查。安全
通过上述对比,能够看到 TypeScript 的出现很好的弥补了 JavaScript 的部分设计缺陷,给咱们带来了很大的便利,也提升了代码的健壮性和扩展性。闭包
基础数据类型包括:Boolean、Number、String、Array、Enum、Any、Unknown、Tuple、Void、Null、Undefined、Never。下面选择几个 TypeScript 特有的类型进行详解:编程语言
// 包括 数字枚举、字符串枚举、异构枚举(数字和字符串的混合)。 // 数字枚举在不设置默认值的状况下,默认第一个值为0,其余依次自增加 enum STATUS { PENDING, PROCESS, COMPLETED, } let status: STATUS = STATUS.PENDING; // 0
Unknown 类型:Unknown 类型也是顶层类型,它能够接收任何类型,但它与 Any 的区别在于,它首次赋值后就肯定了数据类型,不容许变量的数据类型进行二次变动。因此,在须要接收全部类型的场景下,优先考虑用 Unknown 代替 Any。ide
let tupleType: [string, boolean]; tupleType = ["momo", true];
:
冒号后面注明变量的类型便可。const str: string = 'abc';
应用场景:好比咱们在实现订单相关功能的时候,须要对订单进行抽象,定义一个订单的接口,包括订单基本信息以及对订单的相关操做,而后基于这个接口来作进一步的实现。后续若是订单的相关操做功能有变化,只须要从新定义一个类来实现这个接口便可。模块化
interface Animal { name: string; getName(): string; } class Monkey implements Padder { constructor(private name: string) { getName() { return 'Monkey: ' + name; } } }
属性和方法
class Person { // 静态属性 static name: string = "momo"; // 成员属性 gender: string; // 构造函数 constructor(str: string) { this.gender = str; } // 静态方法 static getName() { return this.name; } // 成员方法 getGender() { return 'Gender: ' + this.gender; } } let person = new Person("female");
getter 和 setter
class Person { private _name: string; get name(): string { return this._name; } set name(newName: string) { this._name = newName; } } let person = new Person('momo'); console.log(person.name); // momo person.name = 'new_momo'; console.log(person.name); // new_momo
继承
class Animal { name: string; constructor(nameStr=:string) { this.name = nameStr; } move(distanceInMeters: number = 0) { console.log(`${this.name} moved ${distanceInMeters}m.`); } } class Snake extends Animal { constructor(name: string) { super(name); } move(distanceInMeters = 5) { super.move(distanceInMeters); } } let snake = new Snake('snake'); snake.move(); // 输出:'snake moved 5m'
私有字段
#
字符开头。私有字段不能在包含的类以外访问,甚至不能被检测到。class Person { #name: string; constructor(name: string) { this.#name = name; } greet() { console.log(`Hello, ${this.#name}!`); } } let person = new Person('momo'); person.#name; // 访问会报错
泛型接口
interface identityFn<T> { (arg: T): T; }
泛型类
class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function (x, y) { return x + y; };
泛型变量
使用大写字母 A-Z 定义的类型变量都属于泛型,常见泛型变量以下:
交叉类型就是将多个类型合并为一个类型。经过 &
运算符定义。以下示例中,将 Person 类型和 Company 类型合并后,生成了新的类型 Staff,该类型同时具有这两种类型的全部成员。
interface Person { name: string; gender: string; } interface Company { companyName: string; } type Staff = Person & Company; const staff: Staff = { name: 'momo', gender: 'female', companyName: 'ZCY' };
联合类型就是由具备或关系的多个类型组合而成,只要知足其中一个类型便可。经过 |
运算符定义。以下示例中,函数的入参为 string 或 number 类型便可。
function fn(param: string | number): void { console.log("This is the union type"); }
类型保护就是在咱们已经识别到当前数据是某种数据类型的状况下,安全的调用这个数据类型对应的属性和方法。经常使用的类型保护包括 in
类型保护、typeof
类型保护、instanceof
类型保护和 自定义
类型保护。具体见如下示例:
in
类型保护
interface Person { name: string; gender: string; } interface Employee { name: string; company: string; } type UnknownStaff = Person | Employee; function getInfo(staff: UnknownStaff) { if ("gender" in staff) { console.log("Person info"); } if ("company" in staff) { console.log("Employee info"); } }
typeof
类型保护
function processData(param: string | number): unknown { if (typeof param === 'string') { return param.toUpperCase() } return param; }
instanceof
类型保护:和 typeof
类型用法类似,它主要是用来判断是不是一个类的对象或者继承对象的。function processData(param: Date | RegExp): unknown { if (param instanceof Date) { return param.getTime(); } return param; }
自定义
类型保护:经过类型谓词 parameterName is Type
来实现自定义类型保护。以下示例,实现了接口的请求参数的类型保护。interface ReqParams { url: string; onSuccess?: () => void; onError?: () => void; } // 检测 request 对象包含参数符合要求的状况下,才返回 url function validReqParams(request: unknown): request is ReqParams { return request && request.url }
?.
if(result && result.data && result.data.list) // JS if(result?.data?.list) // TS
??
let temp = (val !== null && val !== void 0 ? val : '1'); // JS let temp = val ?? '1'; // TS
不要彻底依赖于类型检查,必要时仍是须要编写兜底的防护性代码。
function fn(value:boolean){ switch(value){ case true: console.log('true'); break; case false: console.log('false'); break; default: console.log('dead code'); } }
// 推荐写法 function getLocalStorage<T>(key: string): T | null { const str = window.localStorage.getItem(key); return str ? JSON.parse(str) : null; } const data = getLocalStorage<DataType>("USER_KEY");
利用 new() 实现工厂模式
function create<T>(c: { new(): T }): T { return new c(); } class Test { constructor() { } } create(Test);
function fn(arr:readonly number[] ){ let sum=0, num = 0; while((num = arr.pop()) !== undefined){ sum += num; } return sum; }
// 使用 const enum 维护常量 const enum PROJ_STATUS { PENDING = 'PENDING', PROCESS = 'PROCESS', COMPLETED = 'COMPLETED' } function handleProject (status: PROJ_STATUS): void { } handleProject(PROJ_STATUS.COMPLETED)
{ "compilerOptions": { /* 严格的类型检查选项 */ "strict": true, // 启用全部严格类型检查选项 "noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错 "strictNullChecks": true, // 启用严格的 null 检查 "noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误 "alwaysStrict": true, // 以严格模式检查每一个模块,并在每一个文件里加入 'use strict' /* 额外的检查 */ "noUnusedLocals": true, // 有未使用的变量时,抛出错误 "noUnusedParameters": true, // 有未使用的参数时,抛出错误 "noImplicitReturns": true, // 并非全部函数里的代码都有返回值时,抛出错误 "noFallthroughCasesInSwitch": true,// 报告 switch 语句的 fallthrough 错误。(即,不容许 switch 的 case 语句贯穿) } }
TypeScript Extension Pack,它集合了咱们平常经常使用的 TypeScript 相关插件:
Ctrl+Opt+o
,Win/Linux 上快捷键 Ctrl+Alt+o
。Ctrl+Opt+V
,Win/Linux 上快捷键 Ctrl+Alt+V
。政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 40 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在平常的业务对接以外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推进并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。
若是你想改变一直被事折腾,但愿开始能折腾事;若是你想改变一直被告诫须要多些想法,却无从破局;若是你想改变你有能力去作成那个结果,却不须要你;若是你想改变你想作成的事须要一个团队去支撑,但没你带人的位置;若是你想改变既定的节奏,将会是“5 年工做时间 3 年工做经验”;若是你想改变原本悟性不错,但老是有那一层窗户纸的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但愿参与到随着业务腾飞的过程,亲手推进一个有着深刻的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我以为咱们该聊聊。任什么时候间,等着你写点什么,发给 ZooTeam@cai-inc.com