美文网首页
TypeScript 详解之 TypeScript 的对象类型

TypeScript 详解之 TypeScript 的对象类型

作者: you的日常 | 来源:发表于2023-08-13 10:48 被阅读0次

简介

除了原始类型,对象是 JavaScript 最基本的数据结构。TypeScript 对于对象类型有很多规则。

对象类型的最简单声明方法,就是使用大括号表示对象,在大括号内部声明每个属性和方法的类型。

const obj:{
  x:number;
  y:number;
} = { x: 1, y: 1 };

上面示例中,对象obj的类型就写在变量名后面,使用大括号描述,内部声明每个属性的属性名和类型。

属性的类型可以用分号结尾,也可以用逗号结尾。

// 属性类型以分号结尾
type MyObj = {
  x:number;
  y:number;
};

// 属性类型以逗号结尾
type MyObj = {
  x:number,
  y:number,
};

最后一个属性后面,可以写分号或逗号,也可以不写。

一旦声明了类型,对象赋值时,就不能缺少指定的属性,也不能有多余的属性。

type MyObj = {
  x:number;
  y:number;
};

const o1:MyObj = { x: 1 }; // 报错
const o2:MyObj = { x: 1, y: 1, z: 1 }; // 报错

上面示例中,变量o1缺少了属性y,变量o2多出了属性z,都会报错。

读写不存在的属性也会报错。

const obj:{
  x:number;
  y:number;
} = { x: 1, y: 1 };

console.log(obj.z); // 报错
obj.z = 1; // 报错

上面示例中,读写不存在的属性z都会报错。

同样地,也不能删除类型声明中存在的属性,修改属性值是可以的。

const myUser = {
  name: "Sabrina",
};

delete myUser.name // 报错
myUser.name = "Cynthia"; // 正确

上面声明中,删除类型声明中存在的属性name会报错,但是可以修改它的值。

对象的方法使用函数类型描述。

const obj:{
  x: number;
  y: number;
  add(x:number, y:number): number;
  // 或者写成
  // add: (x:number, y:number) => number;
} = {
  x: 1,
  y: 1,
  add(x, y) {
    return x + y;
  }
};

上面示例中,对象obj有一个方法add(),需要定义它的参数类型和返回值类型。

对象类型可以使用方括号读取属性的类型。

type User = {
  name: string,
  age: number
};
type Name = User['name']; // string

上面示例中,对象类型User使用方括号,读取了属性name的类型(string)。

除了type命令可以为对象类型声明一个别名,TypeScript 还提供了interface命令,可以把对象类型提炼为一个接口。

// 写法一
type MyObj = {
  x:number;
  y:number;
};

const obj:MyObj = { x: 1, y: 1 };

// 写法二
interface MyObj {
  x: number;
  y: number;
}

const obj:MyObj = { x: 1, y: 1 };

上面示例中,写法一是type命令的用法,写法二是interface命令的用法。interface命令的详细解释,以及与type命令的区别,详见《Interface》一章。

注意,TypeScript 不区分对象自身的属性和继承的属性,一律视为对象的属性。

interface MyInterface {
  toString(): string; // 继承的属性
  prop: number; // 自身的属性
}

const obj:MyInterface = { // 正确
  prop: 123,
};

上面示例中,obj只写了prop属性,但是不报错。因为它可以继承原型上面的toString()方法。

可选属性

如果某个属性是可选的(即可以忽略),需要在属性名后面加一个问号。

const obj: {
  x: number;
  y?: number;
} = { x: 1 };

上面示例中,属性y是可选的。

可选属性等同于允许赋值为undefined,下面两种写法是等效的。

type User = {
  firstName: string;
  lastName?: string;
};

// 等同于
type User = {
  firstName: string;
  lastName: string|undefined;
};

上面示例中,类型User的属性lastName可以是字符串,也可以是undefined,就表示该属性可以省略不写。

同理,读取一个可选属性时,有可能返回undefined

type MyObj = {
  x: string,
  y?: string
};

const obj:MyObj = { x: 'hello' };
obj.y.toLowerCase() // 报错

上面示例中,最后一行会报错,因为obj.y有可能是undefined,无法对其调用toLowerCase()

所以,读取可选属性之前,必须检查一下是否为undefined

const user:{
  firstName: string;
  lastName?: string;
} = { firstName: 'Foo'};

if (user.lastName !== undefined) {
  console.log(`hello ${user.firstName} ${user.lastName}`)
}

上面示例中,lastName是可选属性,需要判断是否为undefined以后,才能使用。建议使用下面的写法。

// 写法一
let firstName = (user.firstName === undefined)
  ? 'Foo' : user.firstName;
let lastName = (user.lastName === undefined)
  ? 'Bar' : user.lastName;

// 写法二
let firstName = user.firstName ?? 'Foo';
let lastName = user.lastName ?? 'Bar';

上面示例中,写法一使用三元运算符?:,判断是否为undefined,并设置默认值。写法二使用 Null 判断运算符??,与写法一的作用完全相同。

只读属性

属性名前面加上readonly关键字,表示这个属性是只读属性,不能修改。

interface MyInterface {
  readonly prop: number;
}

上面示例中,prop属性是只读属性,不能修改它的值。

const person:{
  readonly age: number
} = { age: 20 };

person.age = 21; // 报错

上面示例中,最后一行修改了只读属性age,就报错了。

只读属性只能在对象初始化期间赋值,此后就不能修改该属性。

type Point = {
  readonly x: number;
  readonly y: number;
};

const p:Point = { x: 0, y: 0 };

p.x = 100; // 报错

上面示例中,类型Point的属性xy都带有修饰符readonly,表示这两个属性只能在初始化期间赋值,后面再修改就会报错。

注意,如果属性值是一个对象,readonly修饰符并不禁止修改该对象的属性,只是禁止完全替换掉该对象。

interface Home {
  readonly resident: {
    name: string;
    age: number
  };
}

const h:Home = {
  resident: {
    name: 'Vicky',
    age: 42
  }
};

h.resident.age = 32; // 正确
h.resident = {
  name: 'Kate',
  age: 23 
} // 报错

上面示例中,h.resident是只读属性,它的值是一个对象。修改这个对象的age属性是可以的,但是整个替换掉h.resident属性会报错。

另一个需要注意的地方是,如果一个对象有两个引用,即两个变量对应同一个对象,其中一个变量是可写的,另一个变量是只读的,那么从可写变量修改属性,会影响到只读变量。

interface Person {
  name: string;
  age: number;
}

interface ReadonlyPerson {
  readonly name: string;
  readonly age: number;
}

let w:Person = {
  name: 'Vicky',
  age: 42,
};

let r:ReadonlyPerson = w;

w.age += 1;
r.age // 43

上面示例中,变量wr指向同一个对象,其中w是可写的,r的只读的。那么,对w的属性修改,会影响到r

如果希望属性值是只读的,除了声明时加上readonly关键字,还有一种方法,就是在赋值时,在对象后面加上只读断言as const

const myUser = {
  name: "Sabrina",
} as const;

myUser.name = "Cynthia"; // 报错

上面示例中,对象后面加了只读断言as const,就变成只读对象了,不能修改属性了。

相关文章

网友评论

      本文标题:TypeScript 详解之 TypeScript 的对象类型

      本文链接:https://www.haomeiwen.com/subject/fbsnpdtx.html