内容简介:TypeScript 2.9 版本中添加了一个在 NodeJS 中,我们通常会导入一些当重写为 TypeScript 之后,仅仅是将
TypeScript 2.9 版本中添加了一个 resolveJsonModule 编译选项,它允许我们在 TypeScript 模块中导入 JSON 文件。
在 NodeJS 中,我们通常会导入一些 .json 文件,如下所示:
// config.json
{
"debug": true
}
复制代码
const config = require('./config.json');
config.debug === true // true
复制代码
当重写为 TypeScript 之后,仅仅是将 require 语法改写成 ES Module,而不做其他修改,TypeScript 将会抛出错误:
import config from './1.json'; // Error: Cannot find module './1.json' 复制代码
这是由于在默认情况下,相对路径导入模块时,TypeScript 只识别 .ts/tsx 文件模块。如果你使用的是 TypeScript 2.9 前的版本,你可能会用以下方式:
declare module '*.json'; 复制代码
但是它也只 decalre 了一个模块,模块内容还是 any,也就是无法得到一些代码提示(无法得到有关键值对信息)。
TypeScript 2.9 添加 resolveJsonModule 编译选项,很好的解决了这个问题:
unknown 替代 any
使用 TypeScript 的过程中,难免会有使用 any 的情况,这个时候倒不如换个方式,使用 unknown 试试。
unknown 最早出现在此 PR 中,随 3.0 一起发布。它被认为是安全版的 any,与 any 不同的是,unknown 仅能赋值给 any、unknown 类型,以及 unknown 上不存在任何属性与方法。
let a: any = 10; // 任何类型都能赋值给 any let u: unknown = 10; // 与 any 一样,任何类型都能赋值给 unknown let s1: string = a; // any 能赋值给任何类型 let s2: string = u; // 不能把 unknown 赋值给除 any、unknow 以外的其他类型 a.method(); // any 上有任意的属性和方法 u.method(); // unknown 没有被断言到一个确切类型之前,不具备任何属性和方法 复制代码
当然,unknown 也能被断言,或是类型缩小至一个指定的范围:
const name: unknown = 'hello';
const str = name as string; // unknown 断言为 string 类型
const oStr = str.toUpperCase(); // HELLO
function doSome(x: unknown) {
if (typeof x === 'string') {
// 在这个块中,TypeScript 知道 `x` 的类型必须是 `string`
console.log(x.subtr(1)); // Error: 'subtr' 方法并没有存在于 `string` 上
console.log(x.substr(1)); // ok
}
if (x instanceof Date) {
// x 是 Datee 类型
console.log(x.toISOString()); // ok
}
}
复制代码
也可以使用自定义保护类型:
function isNumberArray(value: unknown): value is number[] {
return (
Array.isArray(value) &&
value.every(element => typeof element === "number")
);
}
const unknownValue: unknown = [15, 23, 8, 4, 42, 16];
if (isNumberArray(unknownValue)) {
// unknownValue 类型是 number[]
const max = Math.max(...unknownValue);
console.log(max);
}
复制代码
对于 unknown 的使用,官方推荐的用法是:
我们经常需要在 TypeScript 中描述功能最少的类型。这对于那些「希望是任何类型,但是在使用之前必须执行某种类型检查」非常有用,它强制使用者安全性的思考它返回的值。
此外,在即将发布的 3.5 版本中,泛型参数的隐式类型由 {} 类型,变成 unknown ,即,在 3.5 以下版本时,可以:
function test<T>(params: T) {
return params.toString(); // ok
}
复制代码
3.5 版本以上,这将会报错:
function test<T>(params: T) {
return params.toString(); // ERROR: Property 'toString' does not exist on type 'T'.
}
复制代码
你可以这么做来修复它:
function test<T extends {}>(params: T) {
return params.toString(); // ok
}
复制代码
const 断言
当声明一个可变变量或者属性时,TypeScript 通常会扩展变量类型,来确保我们在不编写显示类型时,可以赋值内容:
let x = 'hello'; // x 的类型是 string // 可以重新赋值 x = 'world'; 复制代码
你也可以声明一个字面量类型,在接下来将不能被重新赋值:
let x: 'hello' = 'hello'; // x 的类型是 hello // 或者是 x = 'hello' as 'hello' // error,不能重新赋值 x = 'world'; 复制代码
这种方式似乎很极端,但在某些情况下,却是很有用:
interface Test {
pos: 'left' | 'right' | 'top' | 'bottom'
}
function func() {
// 可能是经过一系列计算得到的值
return {
pos: 'left'
}
}
// Error: TypeScript 将会把 func 推断为 { pos: string },而不是 { pos: 'left' }
let t: Test = func();
复制代码
你可以通过字面量解决这个问题:
function func() {
// 可能是经过一系列计算得到的值
return {
pos: 'left' as 'left'
}
}
// Error: TypeScript 将会把 func 推断为 { pos: string },而不是 { pos: 'left' }
let t: Test = func();
复制代码
随着数据结构逐渐变得复杂,这种方式变得越来越麻烦,const 断言的出现,正是为了解决这样的问题。
function func() {
// 可能是经过一系列计算得到的值
return {
pos: 'left'
} as const
}
// ok
let t: Test = func();
复制代码
使用 const 断言时:
- 表达式中的字面量类型不应该被扩展(如,不应该从字面量类型
hello到string类型) - 对象字面量类型属性只读
- 数组字面量成为 readonly tuples
即:
let obj = {
x: 10,
y: ['hello', 2'],
z: {
a:
{ b: 'top' }
}
} as const;
// obj 的类型是:
// {
// readonly x: 10;
// readonly y: readonly ["hello", "2"];
// z: {
// a: {
// readonly b: "top";
// };
// };
// }
复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript Patterns
Stoyan Stefanov / O'Reilly Media, Inc. / 2010-09-21 / USD 29.99
What's the best approach for developing an application with JavaScript? This book helps you answer that question with numerous JavaScript coding patterns and best practices. If you're an experienced d......一起来看看 《JavaScript Patterns》 这本书的介绍吧!