TypeScript 2.9 版本中添加了一个 resolveJsonModule
编译选项,它容许咱们在 TypeScript 模块中导入 JSON 文件。html
在 NodeJS 中,咱们一般会导入一些 .json
文件,以下所示:git
// config.json
{
"debug": true
}
复制代码
const config = require('./config.json');
config.debug === true // true
复制代码
当重写为 TypeScript 以后,仅仅是将 require
语法改写成 ES Module,而不作其余修改,TypeScript 将会抛出错误:github
import config from './1.json'; // Error: Cannot find module './1.json'
复制代码
这是因为在默认状况下,相对路径导入模块时,TypeScript 只识别 .ts/tsx
文件模块。若是你使用的是 TypeScript 2.9 前的版本,你可能会用如下方式:typescript
declare module '*.json';
复制代码
可是它也只 decalre
了一个模块,模块内容仍是 any,也就是没法获得一些代码提示(没法获得有关键值对信息)。json
TypeScript 2.9 添加 resolveJsonModule
编译选项,很好的解决了这个问题:数组
使用 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
}
}
复制代码
也可使用自定义保护类型:ui
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
}
复制代码
当声明一个可变变量或者属性时,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
类型)即:
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";
// };
// };
// }
复制代码
更多文章,请关注公众号: