做者:RCjavascript
原文:blog.bitsrc.io/7-new-and-e…html
TypeScript 语言小组一直在以惊人的速度推出新功能。从最新的《 Javascript 语言情况调查》(2019.stateofjs.com/javascript-…java
本文将会总结你应该使用的最重要的功能。我会重点介绍如下最新版本的功能:webpack
注意:在探究这些功能以前,你应该先去看一下 TypeScript playground,在这里能够测试全部的功能。我建议你切换到较旧的版本(单击左上角的版本下拉列表),来查看较新的版本是怎样处理之前不支持的用例的:web
从 v3.7 可用typescript
这是当你尝试访问嵌套数据时的一个痛点,嵌套数据越多,代码就会变得越繁琐。数组
在下面的例子中,要访问 address
,你必须遍历 data.customer.address
,并且 data
或 customer
有多是 undefined
,因此一般使用 &&
运算符或相似例子中的技巧遍历检查每一个层次的定义。缓存
如今你能够用 .?
运算符来选择性地对数据访问。经过这种方式,若是存在还没有定义的父级对象,则会在链中的任何位置返回未定义,而不是在运行时崩溃。app
// v3.7 之前
if (data && data.customer && data.customer.address) {
const {address} = data.customer
const fullAddress = `${address.street}, ${address.city}, ${address.state }${address.zipcode}`
}
// v3.7
// data access
const address = data?.customer?.address
const fullAddress = `${address?.street}, ${address?.city}, ${address?.state } ${address?.zipcode}`
// 也适用于数组
customers?.[0]?.['address']
// 检查方法是否已定义并调用
customer.approve?.()
复制代码
从 v3.7 可用async
空值合并运算符是 ||
的替代方法,若是左侧是 null
或 undefined
,则它返回右侧的表达式。这和 ||
有什么不一样? ||
本质上是 JavaScript 中的布尔 OR 运算符,咱们尝试利用短路返回第一个非 false 值。这可能会产生意想不到的结果,由于当要求数字 0 或空字符串做为有效输入时,将会被视为 false
。让咱们用一个例子来讲明:
// 之前
passPhrase = data.inputString || 'Unknown' //不会接受 "" (空字符串)
passCode = data.number || '-1111' // 不会接受 0
rememberMe = data.rememberFlag || true // 将会老是 true!!!
// 如今
passPhrase = data.inputString ?? 'Unknown' //仅在 inputString 未定义时为 Unknown
passCode = data.number ?? '-1111' // 0 能够经过
rememberMe = data.rememberFlag ?? true // false 是有效值
复制代码
经过这种方式能够明确地区分 undefined
与 false
的值。
从 v3.7 可用
现实世界中的不少数据类型都是递归的。例如,当你尝试处理分层数据时,会发现存在相同类型数据的重复模式。 JSON 是一个很好的例子,它本质上是一个哈希映射,而哈希映射自己能够包含另外一个映射或映射数组。
在 v3.6 以前,若是必须定义一个简单的 JSON 类型,则必须像下面这样:
interface JSONObject { [x: string]: JSONValue; }
interface JSONArray extends Array<JSONValue> { }
type JSONValue = string | number | boolean | JSONObject | JSONArray
复制代码
若是你尝试将第 1 行和第 2 行的类型在像第 3 那样内联,则可能会出现如下错误:Type alias JSONValue circularly references itself
。
在 v3.7 中已经有效解决了这个问题,能够像下面这样简单地进行编码:
type JSONValue = string | number | boolean | { [x: string]: JSONValue } | Array<JSONValue>
复制代码
从 v3.7 可用
你应该知道 TypeScript 具备类型保护,能够很好地与 JavaScript 中的 typeof
和 instanceOf
运算符一块儿使用。这有助于为函数的参数添加前提条件,以便将其限制为特定的类型。
让咱们写一段把上面提到的这些东西都用到的代码,经过添加类型保护来确保给定的输入是日期,并从中提取年份:
function isDate(input: unknown) : asserts input is Date {
if (input instanceof Date)
return;
else
throw new Error('Input must be a Date!');
}
function getYear(input: unknown) : number {
isDate(input);
return input.getFullYear() // TypeScripts knows that input is Date
}
console.log(getYear(new Date('2019-01-01')));
console.log(getYear('2019-01-01'));
复制代码
上面的代码看起来很不错,但 TypeScript 仍然会提示getFullYear 在未知类型上不可用
。
从 v3.7 开始,TypeScript 添加了一个名为 asserts
的新关键字,它可以使编译器从断言起就知道正确的类型。对于断言函数,应该添加 asserts <param> as <type>
而不是返回类型。
这样,若是断言经过,TypeScript 将假定参数是前面定义的类型。修改后的代码以下所示:
function isDate(input: unknown) : asserts input is Date {
if (input instanceof Date)
return;
else
throw new Error('Input must be a Date!');
}
function getYear(input: unknown) : number {
isDate(input);
return input.getFullYear() // TypeScripts knows that input is Date
}
console.log(getYear(new Date('2019-01-01')));
console.log(getYear('2019-01-01'));
复制代码
从 3.6 起改进
在代码中直接使用 Promise 而忘记使用 await
或 then
是常见的错误,以下所示:
interface Customer {
name: string
phone: string
}
declare function getCustomerData(id: string): Promise<Customer>; declare function payCustomer(customer: Customer): void; async function f() {
const customer = getCustomerData('c1')
payCustomer(customer)
}
复制代码
之前的 TypeScript 彻底不了解 Promise,并显示一条与其无关的错误消息,以下所示:
从 v3. 6 开始,编译器变得很是聪明,能够建议你应该兑现 Promise。注意最新的编译器是如何处理相同的错误的:
下面简单讨论一下不须要深刻了解细节的一些功能:
从 v3.6 可用
const 𝓱𝓮𝓵𝓵𝓸 = "world"
复制代码
上面的代码可能不可以在早期版本的 TypeScript 上编译,可是如今你能够从更普遍的 unicode 集中定义标识符。
从 v3.4 起可用
若是你在大型项目上使用 TypeScript,则编译器可能须要很长时间才能响应你对该代项目中文件所作的更改。如今有了新的 --incremental
标志,你能够将其添加到 tsc
(typescript 编译器)命令行中,这个命令行将会递增地编译修改过的文件。
TypeScript 经过把自从上次编译以来的项目信息保存在代码库内的本地缓存目录中来实现这一目的。在 React 代码库上,必定要记住在 Webpack 或 Parcel 进行正确的配置,这样才能在构建管道中利用增量编译。