经过示例演示 TypeScript 的高级类型

原文地址: levelup.gitconnected.com/advanced-ty…
译文地址:github.com/xiao-T/note…
本文版权归原做者全部,翻译仅用于学习。css


提高你对 TypeScript 的理解,并学这些高级的技术,能够帮助你掌握该语言而且能够更好的在 React 中使用 TypeScript。git

去年冬天,我开始使用 TypeScript,我已经从一个使用 any 的新手逐渐成长为一个习惯使用高级内置类型和自定义类型的老手。经过在 JavaScript 代码添加类型判断,让应用变得更加健壮。这篇文章提供了一些使用高级类型的示例,也展现了如何在 React 应用使用它们。github

在这里,咱们将会探讨 RecordPartialRequiredPick 和一个自定义Omit 类型。typescript

Record

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,用户能够添加到购物车:编辑器

你会看到编辑器是如何自动帮咱们定义对象类型的,同时也会标记出错误提示,这是由于一些必要的属性没有定义:函数

img

另外,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 and Required

Partial 可让对象中全部的属性变成可选的。在不少状况它能够帮到你,好比,当你须要数据渲染组件时,可是,你知道在组件 mount 时并不会加载数据:

你还也能够用 Partial 来为组件定义默认的 props。

相反,TypeScript v2.8 中引入的 Required ,可让对象中的全部的属性变成必选的:

Required 的用例之一就是 selectors:有时你想为嵌套对象中的属性创造选择器,而且,你知道在选择器调用时将会定义此属性。你能够为此指定一个类型:

这看起来像是做弊,若是,你从可选属性继承必选属性可能会引发类型错误,所以,要当心使用!

听起来很傻,可是,若是你的代码是自动生成的,而且,你全部的 interface 都是 Partial,UI 中全部的元素都是 Required,这种状况并不稀奇。这时你须要检查全部 undefined 的对象 😨。

Pick and Omit

曾经,你是否想过缩减一连串的类型,由于,你意识到下一个 class 并不须要这么多属性?或许你在重构时遇到这类问题,尝试以一种全新的方式分布系统的每一部分。这里有几种方式能够解决这类问题。

Pick 可让你在一个已经定义好的 interface 中挑选你须要的 key。

Omit 在 TypeScript 的 lib.d.ts 中并无预先定义,可是,它能够很容易经过 PickExclude 来定义。它能够从一个 interface 中排除掉你不想要的属性。

下面两张图片中,ProductPhotoProps 会包含 Product 全部的属性,name 和 descripition 除外:

其中一个实际示例,就来自个人项目:重构一个有着复杂依赖的庞大表单。有一个 FormProps 它包含了错误类型。从新思考后,对于第一个子组件这些错误类型并非必要的,可是,第二个组件仍然须要。除了错误类型,我用 Pick 提取了一些属性构建了一个新的 interface,这种方式工做的很好。

固然,有多种方式能够合并类型和定义它们之间的关系。若是,从一开始你就把很大一块东西拆解成不少小块,你或许解决了从对象中排除属性的问题。可是,你会遇到扩展类型的问题。

继承扩展 type/interface

当你须要扩展一个 interface 时,全部的属性在新的 interface 都有效。咱们来看看,如何合并多个小的 interface 以便符合的咱们的任务需求:

这种方法并非很方便,由于,你必须更有预见性考虑你的对象。从另外一方面来说,它更加快速和简单,让你设计原型或者构建简单 UI 更加炫酷,就像是把数据选到一个只读块中。

总结

经过一些真实代码,我已经介绍了比较流行的 TypeScript 内置的类型。这只是一个 demo,可是,我知道这全部的类型至少会在一个真实场景中有效😉。我但愿这篇文章能帮助到你,而且,鼓励你不要惧怕 TypeScript。我用 React-Redux 建立了一个 SPA 的代码仓,在这里你能够找到大多数的演示或者它们的替代方案。

然而,针对静态类型我还想多说一些。一般,当你探索一种新技术或者面对一个开发中的挑战时,你开始解决技术问题,反而忘记了你的目的。静态类型并非你工做的目的,它只是一个工具。若是,它成为了项目中的核心,这表明着你已经走偏了🚀。记住要在业务和技术之间作好平衡,编码快乐!

相关文章
相关标签/搜索