TypeScript数组类型

数组是十分常用的数据结构,它表示一组有序元素的集合。在TypeScript中,数组值的数据类型为数组类型

数组类型定义

TypeScript提供了以下两种方式来定义数组类型:

  • 简便数组类型表示法。
  • 泛型数组类型表示法。

以上两种数组类型定义方式仅在编码风格上有所区别,两者在功能上没有任何差别。

简便数组类型表示法

简便数组类型表示法借用了数组字面量的语法,通过在数组元素类型之后添加一对方括号“[]”来定义数组类型。它的语法如下所示:

TElement[]

该语法中,TElement代表数组元素的类型,方括号“[]”代表数组类型。在TElement与“[]”之间不允许出现换行符号

下例中,我们使用“number[]”类型注解定义了常量digits的类型为number数组类型,它表示digits数组中元素的类型为number类型。示例如下:

const digits: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

如果数组中元素的类型为复合类型,则需要在数组元素类型上使用分组运算符,即小括号

例如,下例中的red数组既包含字符串元素也包含数字元素。因此,red数组元素的类型为string类型和number类型构成的联合类型,即“string | number”

在使用简便数组类型表示法时,必须先将联合类型放在分组运算符内,然后再在后面添加一对方括号。示例如下:

const red: (string | number)[] = ['f', f, 0, 0, 0, 0];

此例中,若在类型注解里没有使用分组运算符,则表示string类型和number[]类型的联合类型,即“string | (number[])”。该类型与实际数组类型不兼容,因此将产生编译错误。示例如下:

const red: string | number[] = ['f', 'f', 0, 0, 0, 0];
//    ~~~
//    编译错误

泛型数组类型表示法

泛型数组类型表示法是另一种表示数组类型的方法。顾名思义,泛型数组类型表示法就是使用泛型来表示数组类型。它的语法如下所示:

Array<TElement>

该语法中,Array代表数组类型;“<TElement>”是类型参数的语法,其中TElement代表数组元素的类型。

下例中,我们使用“Array<number>”类型注解定义了常量digits的类型为number数组类型,它表示digits数组中元素的类型为number类型。示例如下:

const digits: Array<number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

在使用泛型数组类型表示法时,就算数组中元素的类型为复合类型也不需要使用分组运算符。我们还是以既包含字符串元素也包含数字元素的red数组为例,示例如下:

const red: Array<string | number> = ['f', 'f', 0, 0, 0, 0];

此例中,我们不再需要对联合类型“string | number”使用分组运算符。

两种方法比较

正如前文所讲,简便数组类型表示法和泛型数组类型表示法在功能上没有任何差别,两者只是在编程风格上有所差别。

在定义简单数组类型时,如数组元素为单一原始类型或类型引用,使用简便数组类型表示法更加清晰和简洁。示例如下:

let a: string[];

let b: HTMLButtonElement[];

如果数组元素是复杂类型,如对象类型和联合类型等,则可以选择使用泛型数组类型表示法。它也许能让代码看起来更加整洁一些。示例如下:

let a: Array<string | number>;

let b: Array<{ x: number; y: number }>;

总结起来,目前存在以下三种常见的编码风格供读者参考:

  • 始终使用简便数组类型表示法。
  • 始终使用泛型数组类型表示法。
  • 当数组元素类型为单一原始类型或类型引用时,始终使用简便数组类型表示法;在其他情况下不做限制。

数组元素类型

在定义了数组类型之后,当访问数组元素时能够获得正确的元素类型信息。示例如下:

const digits: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

const zero = digits[0];
//    ~~~~
//    number类型

此例中,虽然没有给常量zero添加类型注解,但是TypeScript编译器能够从数组类型中推断出zero的类型为number类型。

我们知道,当访问数组中不存在的元素时将返回undefined值。TypeScript的类型系统无法推断出是否存在数组访问越界的情况,因此即使访问了不存在的数组元素,还是会得到声明的数组元素类型。示例如下:

const digits: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

// 没有编译错误
const out: number = digits[100];

只读数组

只读数组与常规数组的区别在于,只读数组仅允许程序读取数组元素而不允许修改数组元素

TypeScript提供了以下三种方式来定义一个只读数组:

  • 使用“ReadonlyArray<T>”内置类型。
  • 使用readonly修饰符。
  • 使用“Readonly<T>”工具类型。

以上三种定义只读数组的方式只是语法不同,它们在功能上没有任何差别。

ReadonlyArray

在TypeScript早期版本中,提供了“ReadonlyArray<T>”类型专门用于定义只读数组。在该类型中,类型参数T表示数组元素的类型。示例如下:

const red: ReadonlyArray<number> = [255, 0, 0];

此例中,定义了只读数组red,该数组中元素的类型为number。

readonly

TypeScript 3.4版本中引入了一种新语法,使用readonly修饰符能够定义只读数组。在定义只读数组时,将readonly修饰符置于数组类型之前即可。示例如下:

const red: readonly number[] = [255, 0, 0];

注意,readonly修饰符不允许与泛型数组类型表示法一起使用。示例如下:

const red: readonly Array<number> = [255, 0, 0];
//         ~~~~~~~~
//         编译错误

Readonly

“Readonly<T>”是TypeScript提供的一个内置工具类型,用于定义只读对象类型。该工具类型能够将类型参数T的所有属性转换为只读属性,它的定义如下所示:

type Readonly<T> = {
   readonly [P in keyof T]: T[P];
};

由于TypeScript 3.4支持了使用readonly修饰符来定义只读数组,所以从TypeScript 3.4开始可以使用“Readonly<T>”工具类型来定义只读数组。示例如下:

const red: Readonly<number[]> = [255, 0, 0];

需要注意的是,类型参数T的值为数组类型“number[]”,而不是数组元素类型number。在这一点上,它与“ReadonlyArray<T>”类型是有区别的。

注意事项

我们可以通过数组元素索引来访问只读数组元素,但是不能修改只读数组元素。示例如下:

const red: readonly number[] = [255, 0, 0];

red[0];         // 正确

red[0] = 0;     // 编译错误

在只读数组上也不支持任何能够修改数组元素的方法,如push和pop方法等。示例如下:

const red: readonly number[] = [255, 0, 0];

red.push(0);     // 编译错误
red.pop();       // 编译错误

在进行赋值操作时,允许将常规数组类型赋值给只读数组类型,但是不允许将只读数组类型赋值给常规数组类型。换句话说,不能通过赋值操作来放宽对只读数组的约束。示例如下:

const a: number[] = [0];
const ra: readonly number[] = [0];

const x: readonly number[] = a;  // 正确

const y: number[] = ra;          // 编译错误

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!