原文地址: levelup.gitconnected.com/advanced-ty…
译文地址:github.com/xiao-T/note…
本文版权归原做者全部,翻译仅用于学习。css
提高你对 TypeScript 的理解,并学这些高级的技术,能够帮助你掌握该语言而且能够更好的在 React 中使用 TypeScript。git
去年冬天,我开始使用 TypeScript,我已经从一个使用 any
的新手逐渐成长为一个习惯使用高级内置类型和自定义类型的老手。经过在 JavaScript 代码添加类型判断,让应用变得更加健壮。这篇文章提供了一些使用高级类型的示例,也展现了如何在 React 应用使用它们。github
在这里,咱们将会探讨 Record
、Partial
、 Required
、 Pick
和一个自定义Omit
类型。typescript
Typescript 2.1 引入了一个很是有用的内置 type Record
:它能够建立类型 map
,并且,很是适合建立复合型的 interface。为了让变量成为 Record
类型,你须要传入一个字符串做为 key 和一些相关的 type。最简单状况是,你有一个 string
做为值的类型。安全
const SERVICES: Record<string, string> = {
doorToDoor: "delivery at door",
airDelivery: "flying in",
specialDelivery: "special delivery",
inStore: "in-store pickup",
};
复制代码
这显得微不足道,可是,它为你平常编码中提供更简单的方式定义类型。一种常见的状况是:当你须要把整个业务总体的 interface 做为键值对保存在字典中时,Record
就很是有用。这个 model 能够表示联系人、事件、用户数据、交通请求、电影票据等,各类集合。在接下来的演示中,咱们为 product 建立了一个 model,用户能够添加到购物车:编辑器
你会看到编辑器是如何自动帮咱们定义对象类型的,同时也会标记出错误提示,这是由于一些必要的属性没有定义:函数
另外,TypeScript 不容许咱们为一些定义好的 type 建立空对象,须要提供相关的属性,可是,这时 Record
就有用处了。工具
另外,也能够用 string
enum
做为 Record
的 key。例如,咱们将会用 ErrorsEnum
来保存访问相关的错误信息:学习
咱们来看看在 Material-UI 中它是如何加强类型的。就如指南中所说,你可使用 CSS-in-JS 添加自定义的样式,而后,经过
withStyles
HOC 注入。你能够经过一个函数定义样式,函数接受一个名theme
的参数,而后,返回相关样式的className
,还能够为这个函数定义类型:ui
你应该注意到,由于每一个样式对象添加了 as CSSProperties
,因此变得很是麻烦。另外,你就可使用 Record
带来的好处:定一个带有类型的 styles
函数:
如今,你能够在任何组件中安全的使用它,而且会摆脱明肯定义 CSS properties 的束缚。
Partial
可让对象中全部的属性变成可选的。在不少状况它能够帮到你,好比,当你须要数据渲染组件时,可是,你知道在组件 mount 时并不会加载数据:
你还也能够用 Partial
来为组件定义默认的 props。
相反,TypeScript v2.8 中引入的 Required
,可让对象中的全部的属性变成必选的:
Required 的用例之一就是 selectors:有时你想为嵌套对象中的属性创造选择器,而且,你知道在选择器调用时将会定义此属性。你能够为此指定一个类型:
这看起来像是做弊,若是,你从可选属性继承必选属性可能会引发类型错误,所以,要当心使用!
听起来很傻,可是,若是你的代码是自动生成的,而且,你全部的 interface 都是 Partial,UI 中全部的元素都是 Required,这种状况并不稀奇。这时你须要检查全部 undefined 的对象 😨。
曾经,你是否想过缩减一连串的类型,由于,你意识到下一个 class 并不须要这么多属性?或许你在重构时遇到这类问题,尝试以一种全新的方式分布系统的每一部分。这里有几种方式能够解决这类问题。
Pick
可让你在一个已经定义好的 interface 中挑选你须要的 key。
Omit
在 TypeScript 的 lib.d.ts
中并无预先定义,可是,它能够很容易经过 Pick
和 Exclude
来定义。它能够从一个 interface 中排除掉你不想要的属性。
下面两张图片中,ProductPhotoProps
会包含 Product
全部的属性,name 和 descripition 除外:
其中一个实际示例,就来自个人项目:重构一个有着复杂依赖的庞大表单。有一个
FormProps
它包含了错误类型。从新思考后,对于第一个子组件这些错误类型并非必要的,可是,第二个组件仍然须要。除了错误类型,我用 Pick 提取了一些属性构建了一个新的 interface,这种方式工做的很好。
固然,有多种方式能够合并类型和定义它们之间的关系。若是,从一开始你就把很大一块东西拆解成不少小块,你或许解决了从对象中排除属性的问题。可是,你会遇到扩展类型的问题。
当你须要扩展一个 interface 时,全部的属性在新的 interface 都有效。咱们来看看,如何合并多个小的 interface 以便符合的咱们的任务需求:
这种方法并非很方便,由于,你必须更有预见性考虑你的对象。从另外一方面来说,它更加快速和简单,让你设计原型或者构建简单 UI 更加炫酷,就像是把数据选到一个只读块中。
经过一些真实代码,我已经介绍了比较流行的 TypeScript 内置的类型。这只是一个 demo,可是,我知道这全部的类型至少会在一个真实场景中有效😉。我但愿这篇文章能帮助到你,而且,鼓励你不要惧怕 TypeScript。我用 React-Redux 建立了一个 SPA 的代码仓,在这里你能够找到大多数的演示或者它们的替代方案。
然而,针对静态类型我还想多说一些。一般,当你探索一种新技术或者面对一个开发中的挑战时,你开始解决技术问题,反而忘记了你的目的。静态类型并非你工做的目的,它只是一个工具。若是,它成为了项目中的核心,这表明着你已经走偏了🚀。记住要在业务和技术之间作好平衡,编码快乐!