typescript学习-object

105 阅读4分钟

在javascript中,组织数据以及传递数据通常都会使用object来完成,在typescript中,object类型有着更加丰富的定义,发挥着更加明显的作用,这篇博客记录一些个人知识的薄弱点

一、如何描述一个object

描述一个对象,可以通过type关键字声明一个类型别名,或者使用interface来定义一个接口。

1.可选属性描述符?

当在操作一个对象时,可能存在部分属性是可选的情况。在typescript中,这种可选属性可以通过操作符?来定义,如下:

type Example = {
  name?:string
}

需要注意的是,可选代表可能不存在,因此name属性的类型是undefined | string的联合类型。

2.可选属性搭配解构赋值

在使用可选属性时,不可避免会遇到空值处理的情况。假如存在以下场景:

interface PaintOptions {
  xPos?: number;
  yPos?: number;
}
function paintShape(opts: PaintOptions) {
  let xPos = opts.xPos === undefined ? 0 : opts.xPos; 
  let yPos = opts.yPos === undefined ? 0 : opts.yPos;     
}

上述代码paintShape函数就是针对空值进行处理,并赋予一个初始值。这种模式虽然增强了代码的健壮性,但当代码中存在很多类似的判断时,不可避免会降低代码的可读性。在这种情况下,就可以使用结构解构**的语法来替代这种冗长的赋值代码。

interface PaintOptions {
  xPos?: number;
  yPos?: number;
}
function paintShape({xPos = 0,yPos = 0}: PaintOptions) {   
}

通过这种方式,极其方便的减少了代码量。

二、索引标签

1.基础定义

在很多时候,我们并不知道一个对象的所有属性,但却知道一个对象的属性结构,在这种情况下,便可以使用索引标签来定义。定义方式如下:

interface StringArray {
  [index: number]: string;
}

此时只要属性名是字符串,属性值也是字符串,便满足结构。需要注意的是,属性名的类型,只能是string | number

2.扩展定义

虽然使用索引标签可以约束对象的部分结构类型,但是也还可以进行扩展定义,比如把已知的属性定义出来。

interface NumberDictionary {
  [index: string]: number;
  length: number; // ok
  name: string; // error
}

这个定义方式表明对象不仅可以有不确定的属性,还有2个确定的属性。但这个地方会产生一个错误,那便是name属性的名称是string,但值是string,不满足满足了索引标签的约束,即属性名是string,则属性值必须是number。此时也可以进行值得扩展,声明为一个联合类型来解决。

interface NumberDictionary {
  [index: string]: number | string;
  length: number; // ok
  name: string; // ok
}

当然这种为了兼容而不断扩大类型范围,本身就会导致定义的约束变宽,这种方式的适用性,还得根据具体的情况来斟酌使用。

三、只读类型的区别

1.只读属性

当声明对象类型时,可以使用修饰符readonly来定义只读属性,但在校验2个类型是否兼容时,并不会考虑只读属性,比如:

type A = {
  readonly a:number
}
type B = {
  a:number
}
let b:B = {
  a:10
}
let a:A = b

上述示例中,虽然A类型和B类型声明上存在区别,但在赋值操作时,类型校验忽略了readonly关键字。

2.只读数组

除了常规使用的数组类型外,还存在一个类型叫只读数组。如下:

let arr:ReadonlyArray<string> = [] // 只读数组
let arr1:Array<string> = []
arr1 = arr // error
arr = arr1 // ok

只读数组不能赋值给一个普通数组,但普通数组可以赋值给一个只读数组

这个地方其实很好理解,数组的赋值操作,本质上是改变了引用的指针。如果只读数组允许赋值给普通数组,那么普通数组可以修改数组,那么此时便会修改到只读数组,所以不允许赋值。反之,只读数组无法修改数组的值,因此不会有影响。

3.只读元组

元组类型是另一种数组类型,简单理解为结构固定的数组类型,可以有定长和不定长2种定义方式。如下:

type StringNumberPair = [string, number]; // 固定长度
type StringNumberBooleans = [string, number, ...boolean[]]; // 不定长度
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];

const a: StringNumberBooleans = ["hello", 1];
const b: StringNumberBooleans = ["beautiful", 2, true];
const c: StringNumberBooleans = ["world", 3, true, false, true, false, true];
const d: StringNumberPair = ['hello',2]

当没有使用省略符时,元组就是长度和类型都确定的数组,当使用了省略符时,元组类型就是不定长的,但固定位置的元素类型被确定

元组通用可以使用readonly来声明,只读元组不允许修改元素内容,这个本质就是和数组一致

type StringNumberPair = readonly [string, number];
let a:StringNumberPair = ['hello',1]
a[1] = 2 // error