前面我们说到了数据类型,像什么布尔类型,数值类型,字符串类型等等,在开发中,我们还会遇到很多像对象、数组、函数等类型,那么在typescript中是怎么定义这些类型的?
对象(object)
我们先介绍下在JavaScript中式怎么定义对象的,在我之前的博客中有提到关于原型链的理解,那里面有对于对象的构造函数-实例对象-原型对象的一个介绍(浅谈我对原型链的理解),这里我再简单说一下,在JavaScript中我们定义对象方式如下:
var person = {
name: 'zhangsan',
age: 18,
sayName: function () {
console.log(this.name)
}
}
可以看到我们创建了一个人物对象,包含人物的姓名,年龄及行为,并且在JavaScript中我们可以随意调用该人物的属性以及随意添加任务新属性,例如:
console.log(person.name); // 获取人物的姓名
console.log(person.age); // 获取人物的年龄
console.log(person.sayName()); // 调用人物的行为
person.gender = 'male'; // 给人物添加新的性别属性
那么在typescript中我们是如何定义对象呢?又是如何获取对象中的属性和定义新的属性呢?
在typescript中,我们定义对象的方式要用到接口,即Interfaces(接口),定义方式如下:
// 我们先定义一个对象的属性,需要注意的是我们使用接口interface定义对象时,接口的首字母最好是大写
interface Person {
name : string ,
age: number
}
我们刚刚定义了一个Person类型的对象,它包含姓名(值类型为字符串类型)和年龄(值类型为数值类型),我们使用方式如下:
let zhangsan : Person {
name : 'zhangsan',
age : 25
}
可以看到,我们定义了一个变量zhangsan,给他定义一个我们创建好的Person类型,同时给属性name和age赋值,这样定义和使用是没有任何问题的,但是,typescript中,我们定义和使用对象属性时需要注意以下几种情况:
(1)使用的类型与定义的类型不一致,例如缺少属性或者新增属性,在typescript中是不允许的,如下:
interface Person {
name : string ,
age: number
}
// 缺省属性
let zhangsan : Person {
name : 'zhangsan'
};
// 新增属性
let zhangsan : Person {
name : 'zhangsan',
age : 25,
weight : 75
};
以上两种情况下,编译均会报错,所以我们可以得知,在typescript中使用的类型与定义的类型必须保持一致,属性不能多也不能少。
但是,这样很不方便,因为我们不知道定义的变量在实际开发中会附上哪些属性,所以typescript中提供了一种方法,也就是任意属性,如下:
interface Person {
name : string ,
[propName: string] : any;
}
let zhangsan : Person {
name : 'zhangsan',
gender : 'male'
};
上面我们定义了一个任意属性,而且编译没有报错,证明我们的代码是没有问题的,不过,这里的任意属性的定义,还有一个值得注意的地方,先看代码:
interface Person {
name : string ,
age : number ,
[propName: string] : any;
}
let zhangsan : Person {
name : 'zhangsan',
age : 25 ,
gender : 'male'
};
这时候你运行代码,会发现报错了:'Property 'age' of type 'number' is not assignable to string index type 'string'.',这报错的意思,我们从字面理解的话就是:'类型为“number”的属性“age”不能分配给字符串索引类型“string”。',我们再深入理解,也就是属性age的number属性不是string类型的子属性。这样就很奇怪了,为什么会报这个错误?
我们可以看下官方文档,原来如果我们在定义接口对象时定义了任意属性,那么这个接口对象内其余的属性就必须是任意属性的子属性,因为我们定义了一个age属性,它的类型是number类型的,而number类型不是string类型以及它的子类型,所以编译时就报错了。
(2)有的类型我们可能用不上,不想去定义,例如性别分为男女,但是还有外星人(当然这里只是调侃一下),这个时候我们不需要性别属性,我们该如何定义?如下:
interface Person {
name : string ,
age: number ,
gender ? : string
}
let zhangsan : Person {
name : 'zhangsan' ,
age : 25
}
可以看到,我们并没有使用Person接口对象内的gender属性,但是编译的时候也没有报错,也就是说gender属性在使用时可有可无。
(3)只可读属性,如下:
interface Person {
name : string ,
age : number ,
readonly id: number
}
在这里我们定义了Person接口对象的属性id为只可读属性,所以我们在初始化变量后,就不能再更改此属性,例如:
interface Person {
name : string ,
age : number ,
readonly id: number
}
let zhangsan: Person = {
name: 'Tom' ,
age: 25 ,
id: 1
};
zhangsan.id = 2; // 编译报错:Cannot assign to 'id' because it is a constant or a read-only property.
这里需要注意一个地方,我们在定义只可读属性时,约束存在于第一次给对象赋值的时候,也是说约束存在于第一次let zhangsan : Person中,而单独赋值(zhangsan.xxxxx)时是不允许的。
到底啦!!!!!!!!