做球服的网站有哪些,国有企业参股管理暂行办法,中国做的儿童编程网站,品牌营销策略先问一个问题#xff0c;JavaScript有几种数据类型#xff1f;number、string、boolean、null、undefined、symbol、bigint、object其中 bigint 是 ES2020 新增的数据类型#xff0c;而早在 TS3.2 时便成为 TS 的标准#xff0c;其实还有好多 ES 标准是 TS 率先提出的… 先问一个问题JavaScript有几种数据类型number、string、boolean、null、undefined、symbol、bigint、object其中 bigint 是 ES2020 新增的数据类型而早在 TS3.2 时便成为 TS 的标准其实还有好多 ES 标准是 TS 率先提出的可见 TS 在很多方面是走在了 ES 前列。TypeScript又新增了多少种数据类型any、unknown、enum、void、never、tuple...其实 TypeScript 更重要的是通过 interface 和 type 赋予了用户自定义数据类型的能力使数据在流转的过程中始终能轻易被用户掌握。Bug 绞杀者TypeScript 可以让我们的程序写的更健壮并且更好维护丰富的代码的提示功能也能够提高我们的开发效率以及降低协作成本并帮助我们在程序的编译阶段检查出许多因为类型的原因导致的低级错误。那么我们先来看下 JavaScript 项目最常见的十大错误这些低级的错误是不是耳熟能详为了解决这些问题占用了我们大量的 debug 和 google 的时间。程序员最烦的两件事一件是自己写完代码还要写注释文档一件是别人的代码没留下任何注释文档。在我们的日常开发中很常见的是调用或者修改别人写的函数。但是如果别人的代码没留下任何注释的话我们就要硬着头皮去看里面的逻辑。假如我们优化了一个底层类库的参数类型而不知道有多少处引用在提交代码前是不是内心在打鼓心里没底呢毕竟我们都不想被杀了祭天吧...笔者前不久就因为一个很小的问题 debug 了很长时间我们来看一下因内部代码所以经过脱敏处理。因为 JavaScript 太灵活了它允许你对参数做任何操作所以之前同学写的时候直接将 userId 挂载到入参 query 上面后面用到处解构也就有了相应的 userId 属性。但是笔者对这部分业务不熟悉以为入参 query 不会改变所以 debug 了好久。而假如我们使用的是 TypeScript 我们会定义好入参 query 的结构为 query 添加 userId 属性的时候就能有报错提示可以规避我们以前的写法换成更健壮性的写法。另外 TypeScript 还能实现自文档化使后面维护的同学也能轻松的接手。我们可以通过/** */来注释 TypeScript 的类型当我们在使用相关类型的时候就会有注释的提示这个技巧可以帮助我们节约翻文档或者跳页看注释的时间在团队内合理的推广使用能够极大的提高我们的开发效率。优化程序性能合理的使用 TypeScript 再凭借 V8 引擎可以帮助我们极大的优化程序的性能。在 V8 引擎下引入了 TurboFan 编译器它会在特定的情况下进行优化将代码编译成执行效率更高的 Machine Code这个编译器虽然不是 JavaScript 必须的但是却能够极大的提高代码执行效能。我们知道 JavaScript 代码首先会解析为抽象语法树AST然后会通过解释器或者编译器转化为 Bytecode 或者 Machine Code。其中 Ignition 负责将 AST 转化为 BytecodeTurboFan 负责编译出优化后的 Machine Code并且 Machine Code 在执行效率上优于 Bytecode。那么问题来了什么情况下的代码会编译为 Machine Code 呢JavaScript 是一门动态类型语言并且有一大堆的隐式类型转换规则比如数字相加、字符串相加、对象和字符串相加等等。这样的情况也就势必导致了内部要增加很多的判断逻辑降低运行时的效率。function test (x) {return x x;
}test(1)
test(2)
test(3)
test(4)
对于上面这段代码来说如果一个函数被多次调用并且参数一直传入 number 类型那么 V8 引擎就会认为该段代码可以编译为 Machine Code因为我们固定了类型不需要再执行很多判断逻辑了。但是一旦我们传入的参数类型改变那么 Machine Code 就会被 DeOptimized 为 Bytecode这样就会造成性能上的损耗。所以如果我们希望代码能尽可能多的编译为 Machine Code 并且 DeOpimized 的次数减少那么我们就应该尽可能的保证传入的类型一致。但是你可能还有一个疑问优化前后的性能提升到底是怎么样的呢有什么数据支撑么const v8 require(v8-natives);
const { performance, PerformanceObserver } require(perf_hooks)function test(x, y) {return x y
}const obs new PerformanceObserver((list, observer) {console.log(list.getEntries())observer.disconnect()
})
obs.observe({ entryTypes: [measure], buffered: true })performance.mark(start)let number 10000000// 不优化代码
v8.neverOptimizeFunction(test)while (number--) {test(1, 2)
}performance.mark(end)
performance.measure(test, start, end)
我们接下来使用 performance 这个 API 测量一下代码的执行时间这个 API 经常用于一些性能测试还可以用来测量各种网络连接中的时间消耗并且也可以在浏览器中使用。我们实际运行一下代码发现经过优化后的代码执行时间只需要 10ms但是不优化的代码却是前者的十二倍高达了 124ms。在这个案例中我们能够看到 V8 的性能优化十分强大只需要我们符合一定规则书写代码引擎底层就能帮助我们自动优化代码。那么为了让 V8 优化代码我们要尽可能的保证传入参数的类型一致而这也正是 TypeScript 带给我们的好处之一借助 TypeScript可以强迫我们思考定义好每一处的变量类型让每一处的变量类型都做到最小可控。使 V8 可以自动将我们的代码优化成 Machine Code。所以我们可以设想一下未来怎么样凭借 TypeScript让 V8 进一步得到优化。1、使用 TypeScript 编程遵循严格的类型化编程规则摒弃 AnyScript。2、构建的时候将 TypeScript 直接编译为 Bytecode而不是 JavaScript 文件这样运行的时候就省去了 Parse 以及生成 Bytecode 的过程。3、运行的时候需要先将 Bytecode 编译为对应 CPU 的汇编代码。这样由于采用了类型化的编程方式有利于编译器优化所生成的汇编代码省去了很多额外的操作。未来的潮流很多的前端底层库都在从 JavaScript 向 TypeScript 迁移像我们熟悉的 Angular 和 Vue3 已经全面用 TypeScript 重构代码在 ECMAScript 标准推出静态类型检查之前TypeScript 是解决当下问题的最佳实践。stackoverflow 统计的2020年最受开发者喜欢的语言TypeScript 已排到第二名。但是很多同学一开始可能不太喜欢使用 TypeScript人们在接触一个新事物的时候往往会出现本能的抗拒因为不太确定这个新的事物能够带给我们什么开发体验的提升。可能有些同学抱着试试看的态度去尝试使用了一下但却发现这个东西巨难用常常代码死活编译不过去各种类型不匹配。一些底层类库的不完善没有很好的支持 TypeScript 也会增加我们开发的上手难度。这也难怪因为 JavaScript 是一门动态弱类型语言对变量的类型非常宽容而且不会在这些变量和它们的调用者之间建立结构化的契约JavaScript 带给我们极大的灵活性。一想到以前快乐的时光可能有的同学直接弃疗重新回到 JavaScript 的怀抱可能有的同学转而去写 AnyScript遇事不决上 any但这是非常差的编程习惯假如我们写 AnyScript我们就失去了 TypeScript 的意义为此我们还要多写好多的冗余代码影响开发效率。其实使用 TypeScript 进行开发理论上我们99.99%的情况都不应该使用 any当我们想要使用 any 的时候就多去思考查阅资料仔细推敲只要我们能够不断忍住不写 any多写 TypeScript写到如臂指使后面你会发现自己的开发效率在不断提升。实用小技巧1. 巧用 keyof假如我们要实现一个 getValue 函数作用是根据传入的 object 和 key 获取 object 上 key 所对应的属性值 value一开始的 JavaScript 版本可能是这样的。const data {a: 3,hello: world
}
function getValue(o, name) {return o[name]
}
可以看到这就是 JavaScript 的弊端我们对传入的 o 和 name 都没有约束对这一切都是未知的人的恐惧就源自对未知事物的不确定性。尤其如果这是一个底层类库我们不知道有多少人去调用那这个风险就更加增大了所以我们可能用 TypeScript 这样去改造它。function getValue(o: any, name: string) {return o[name]
}
但这样写貌似也有很多问题函数返回值的类型变成了 any失去了 TypeScript 类型校验的功能让类型重新变的不可控name 类型固然是 string但还是太宽泛了实际上name 的值只能是o的键的并集而且如果我们将 name 拼写错误TypeScript 也不会帮我们报错提示。这个时候我们可以使用 keyof 结合泛型来加强 getValue 函数的类型功能。function getValueT extends object, K extends keyof T(o: T, name: K): T[K] {return o[name]
}
2. 接口智能提示interface Seal {name: string;url: string;
}
interface API {/user: { name: string; age: number; phone: string };/seals: { seal: Seal[] };
}
const api URL extends keyof API(url: URL): PromiseAPI[URL] {return fetch(url).then((res) res.json());
};
借助泛型以及泛型约束我们可以实现智能提示的功能不光接口名可以智能提示接口返回也可以智能提示。当我们输入 api 的时候其会自动将 API interface 下的所有 key 提示给我们当我们输入某一个 key 的时候其会根据 key 命中的 interface 定义的类型然后给予类型提示。这在统一接口管理方面有很大的用处可以帮助我们面向接口编程。3. 巧用类型保护interface User {name: string;age: number;occupation: string;
}
interface Admin {name: string;age: number;role: string;
}
export type Person User | Admin;
export const persons: Person[] [{name: Max Mustermann,age: 25,occupation: Chimney sweep},{name: Jane Doe,age: 32,role: Administrator},{name: Kate Müller,age: 23,occupation: Astronaut},{name: Bruce Willis,age: 64,role: World saver}
];
export function logPerson(person: Person) {let additionalInformation: string;if (person.role) {additionalInformation person.role;} else {additionalInformation person.occupation;}console.log( - ${person.name}, ${person.age}, ${additionalInformation});
}
persons.forEach(logPerson);
我们可以看到当我们定义了两种 Person 类型User 和 Admin而在使用的时候是比较宽泛的 Person那我们就不能直接使用 User 或者 Admin 的特有属性 role 或者 occupation。因为 TypeScript 没有足够的信息确定 Person 究竟是 User 还是 Admin。一种方法是使用类型断言显示的告诉 TypeScriptperson 就是 Admin 类型或者就是 User 类型但是这样做一方面不够优雅要在每一处都加上断言另一方面滥用断言也会让我们的代码变得不可控不能让 TypeScript 帮助我们进行合理的类型推断。像双重断言可以规避掉 TypeScript 的类型检查机制也是与 any 一样要尽可能去避免的。正确的做法是使用类型收缩比如使用 isintypeofinstanceof 等使得 TypeScript 能够 get 到当前的类型假如 person 上面有 role 属性TypeScript 就可以推断出 person 就是 Admin 类型创建类型保护区块在当前的代码块按照 Admin 类型处理代码也简洁了很多。同样是这个例子我们再改造一下通过两个函数来判断 person 的具体类型是 Admin 还是 User。但是很不幸TypeScript 依然不能很智能的知道 person 在第一个代码块里是 Admin 类型在第二个代码块里是 User 类型。这个时候我们就要改造一下 isAdmin 和 isUser 的函数返回创建用户自定义的类型保护函数显式的告诉 TypeScript函数返回为 true 时指定 person 的类型确定为 Admin 或者 User这样 TypeScript 就知道 person 的确定类型了这就是类型位词。4.常用的高级类型这其实涉及到了类型编程到概念简而言之我们平时写代码是对值进行编程而类型编程是对类型进行编程可以利用 keyof 对属性做一些扩展省的我们要重新定义一下接口造成很多冗余代码。这些高级类型在日常编程中有非常广泛的使用尤其 Partial 可以将所有的属性变成可选的如在我们日常的搜索逻辑我们可以根据单一条件搜索也可以根据组合条件搜索。Omit 可以帮助我们复用一个类型但是又不需要此类型内的全部属性当父组件通过 props 向下传递数据的时候可以剔除一些无用的类型。Record 也是一个比较常用的高级类型可以帮助我们从 Union 类型中创建新类型Union 类型中的值用作新类型的属性。当我们拼写错误或者漏写一些属性或者加入了没有预先定义的属性进去TypeScript 都可以给我们很友好的报错提示。type PartialT {[P in keyof T]?: T[P];
};
type RequiredT {[P in keyof T]-?: T[P];
};
type PickT, K extends keyof T {[P in K]: T[P];
};
type ExcludeT, U T extends U ? never : T;
// 相当于: type A a
type A Excludex | a, x | y | z
type OmitT, K extends keyof any PickT, Excludekeyof T, K;
type RecordK extends keyof any, T {[P in K]: T;
};interface User {id: number;age: number;name: string;
};
// 相当于: type PartialUser { id?: number; age?: number; name?: string; }
type PartialUser PartialUser
// 相当于: type PickUser { id: number; age: number; }
type PickUser PickUser, id | age
// 相当于: type OmitUser { age: number; name: string; }
type OmitUser OmitUser, idtype AnimalType cat | dog | frog;
interface AnimalDescription { name: string, icon: string }
const AnimalMap: RecordAnimalType, AnimalDescription {cat: { name: 猫, icon: },dog: { name: 狗, icon: },forg: { name: 蛙, icon: }, // Hey!
};
5.巧用类型约束在 .tsx 文件中泛型可能会被当作 jsx 标签const toArray T(element: T) [element]; // Error in .tsx file.
加 extends 可破const toArray T extends {}(element: T) [element]; // No errors.
TypeScript 还可以给一些缺乏类型定义的第三方库定义类型找到一些没有 d.ts 声明的开源库为开源社区贡献声明文件。学习参考https://www.typescriptlang.org/docs/handbook/release-notes/overview.html 官方各个版本文档https://github.com/microsoft/TypeScript/projects/9 官方讨论https://github.com/microsoft/vscode VS Code 是 TypeScript 编写的毫无疑问也是学习的好地方https://basarat.gitbook.io/typescript/getting-started TypeScript Deep Divehttps://github.com/typescript-exercises/typescript-exercises TypeScript 优秀的练习题