TypeScript学习【2】TypeScript 的复杂基础类型

下接《TypeScript 的简单基础类型》

数组

数组类型(Array)

在 TypeScript 中,我们也可以像 JavaScript 一样定义数组类型,并且指定数组元素的类型。

首先,我们可以直接使用 [] 的形式定义数组类型,如下所示:

let StringArr: string[] = ['7', 'Jae', 'Pr'];
let NumberArr: number[] = [7, 8, 9];

同样,我们也可以使用 Array 泛型定义数组类型,如下所示:

let StringArr: Array<string> = ['7', 'Jae', 'Pr'];
let NumberArr: Array<number> = [7, 8, 9];

以上两种定义数组类型的方式虽然本质上没有任何区别,但是更推荐使用 [] 这种形式来定义。一方面可以避免与 JSX (一种 JavaScript 的语法扩展,运用于 React 架构中)的语法冲突,另一方面可以减少不少代码量。

如果我们明确指定了数组元素的类型,以下所有操作都将因为不符合类型约定而提示错误:

let NumberArr: number[] = ['x', 'y', 'z']; // 提示 ts(2322)

NumberArr[3] = 'a'; // 提示 ts(2322)

NumberArr.push('b'); // 提示 ts(2345)

let StringArr: string[] = [1, 2, 3]; // 提示 ts(2322)

StringArr[3] = 1; // 提示 ts(2322)

StringArr.push(2); // 提示 ts(2345)

元组类型(Tuple)

元组最重要的特性是可以限制数组元素的个数和类型,它特别适合用来实现多值返回。

网上对于 TS 中元祖类型的解释太过于复杂,我们仅需知道数组是合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。直接看代码示例就好:

let nameAndage: [string, number];
nameAndage[0] = 'Jae';
nameAndage[1] = 23;
// Variable 'xcatliu' is used before being assigned
// 会报错,因为在赋值前使用了变量


// 当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项
let nameAndage: [string, number] = ['Jae'];
// index.ts(1,5): error TS2322: Type '[string]' is not assignable to type '[string, number]'
// 会报错,不能将类型“[string]”分配给类型“[string, number]”。源具有 1 个元素,但目标需要 2 个


let nameAndage: [string, number] = ['Jack', 18];
nameAndage[0] = 'Jae';
nameAndage[1] = 23;
// 一切正常,没有报错

特殊类型

any

any 指的是一个任意类型,它是官方提供的一个选择性绕过静态类型检测的作弊方式。

我们可以对被注解为 any 类型的变量进行任何操作,包括获取事实上并不存在的属性、方法,并且 TypeScript 还无法检测其属性是否存在、类型是否正确。

比如我们可以把任何类型的值赋值给 any 类型的变量,也可以把 any 类型的值赋值给任意类型(除 never 以外)的变量,如下代码所示:

let one: any = {};
one = 1; // 不会报错
one = 'hi'; // 不会报错

let num: number = one; // 不会报错
let str: string = one; // 不会报错

如果我们不想花费过高的成本为复杂的数据添加类型注解,或者已经引入了缺少类型注解的第三方组件库,这时就可以把这些值全部注解为 any 类型,并告诉 TypeScript 选择性地忽略静态类型检测。

尤其是在将一个基于 JavaScript 的应用改造成 TypeScript 的过程中,我们不得不借助 any 来选择性添加和忽略对某些 JavaScript 模块的静态类型检测,直至逐步替换掉所有的 JavaScript。

习惯性地使用 any 是一个坏习惯。如果一个 TypeScript 应用中充满了 any,此时静态类型检测基本起不到任何作用,也就是说与直接使用 JavaScript 没有任何区别。

unknown

unknown 是 TypeScript 3.0 中添加的一个类型,它主要用来描述类型并不确定的变量。

比如在多个 if else 条件分支场景下,它可以用来接收不同条件下类型各异的返回值的临时变量,如下所示:

let res: unknown;
if (x) {
  res = x();
} else if (y) {
  res = y();
}

与 any 不同的是,unknown 在类型上更安全。比如我们可以将任意类型的值赋值给 unknown,但 unknown 类型的值只能赋值给 unknown 或 any,如下代码所示:

let res: unknown;
let num: number = res; // ts(2322) Type 'unknown' is not assignable to type 'number'
let anything: any = res; // 一切正常

使用 unknown 后,TypeScript 会对它做类型检测。但是,如果不缩小类型,我们对 unknown 执行的任何操作都会出现如下所示错误:

let res: unknown;
result.toFixed(); // ts(2571) Object is of type 'unknown'

而所有的类型缩小手段对 unknown 都有效,如下所示:

let res: unknown;
if (typeof res=== 'number') {
  res.toFixed(); // 不会提示错误
}

void、undefined、null

这三种类型没有太大用处,我们只需要了解:

  • void仅适用于表示没有返回值的函数。即如果该函数没有返回值,那它的类型就是 void
  • undefined 的最大价值主要体现在接口类型上,它表示一个可缺省、未定义的属性
  • null 的价值主要体现在接口制定上,它表明对象或属性可能是空值。

never

never 表示永远不会发生值的类型,如下所示:

function throwError(msg: string): never {
  throw Error(msg);
}

以上函数因为永远不会有返回值,所以它的返回值类型就是 never

never 是所有类型的子类型,它可以给所有类型赋值;但是反过来,除了 never 自身以外,其他类型(包括 any 在内的类型)都不能为 never 类型赋值

let res: never;
res = 1; // ts(2322) Type 'number' is not assignable to type 'never'
res = '1'; // ts(2322) Type 'string' is not assignable to type 'never'
let num: number = res; // 一切正常
let str: string = res; // 一切正常

object

object 类型表示非原始类型的类型,即非 number、string、boolean、bigint、symbol、null、undefined 的类型。然而,它也是个没有什么用武之地的类型,这里就不举例了。

类型断言(Type Assertion)

TypeScript 类型检测无法做到绝对智能,毕竟程序不能像人一样思考。有时会碰到我们比 TypeScript 更清楚实际类型的情况,比如下面的例子:

const arrNumber: number[] = [1, 2, 3, 4];
const moreThan2: number = arrNumber.find(num => num > 2); // ts(2322)

其中,moreThan2一定是一个数字(确切地讲是 3),因为 arrNumber中明显有大于 2 的成员,但静态类型对运行时的逻辑无能为力。

在 TypeScript 看来,moreThan2的类型既可能是数字,也可能是 undefined,所以上面的示例中提示了一个 ts(2322) 错误,此时我们不能把类型 undefined 分配给类型 number。

不过,我们可以使用一种笃定的方式——类型断言(类似仅作用在类型层面的强制类型转换)告诉 TypeScript 按照我们的方式做类型检查。

比如,我们可以使用 as 语法做类型断言,如下代码所示:

const arrNumber: number[] = [1, 2, 3, 4];
const moreThan2: number = arrNumber.find(num => num > 2) as number;
console.log(moreThan2); // 3

又或者是使用尖括号 + 类型的格式做类型断言,如下代码所示:

const arrNumber: number[] = [1, 2, 3, 4];
const moreThan2: number = <number>arrNumber.find(num => num > 2);
console.log(moreThan2); // 3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大杯美式不加糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值