新的一天,打卡签到。按照在 Typescript 类型推论 里的约定,咱们将文件 notes/package.json
的 version
改成 0.0.5
,而后 npm run createDir
, 这个时候,notes
目录下就会新增文件夹 0.0.5
,很简单是吧,后面章节,就忽略这些简单操做了,直接奔主题。javascript
在学以前,自觉得对象类型是用 object
来定义,其实否则,在 Typescript 的玩法里,是用接口(Interfaces)来定义。java
面向对象语言中,接口(Interfaces)是对行为的抽象(能够用事物的本质来辅助理解)。而具体如何行动由类(class)来实现(implement)(能够用事物的现象来辅助理解)。react
// interfaces.ts
interface Person {
name: string;
age: number;
}
let pr: Person = {
name: '胖芮',
age: 30
}
复制代码
根据玩法,上面例子中定义了一个接口 Person
(行为的抽象,事物的本质),接着定义了一个变量 pr
,其类型就是 Person
(接口是类型,对象类型)。约束了定义的变量 pr
属性类型必须和接口 Person
一致。git
一般,接口首字母大写(这个能够用 react 组件名称命令规则来辅助理解)。es6
问:定义变量的属性个数比接口少能够么?多一个行不?github
// interfaces2.ts
interface Person2 {
name: string;
age: number;
}
let pr2: Person2 = {
name: '胖芮'
}
// 0.0.5/interfaces2.ts:6:5 - error TS2741: Property 'age' is missing in type '{ name: string; }' but required in type 'Person2'.
// 6 let pr2: Person2 = {
// 0.0.5/interfaces2.ts:3:5
// 3 age: number;
// 'age' is declared here.
复制代码
// interfaces3.ts
interface Person3 {
name: string;
age: number;
}
let pr3: Person3 = {
name: '胖芮',
age: 30,
address: '杭州'
}
// 0.0.5/interfaces3.ts:9:5 - error TS2322: Type '{ name: string; age: number; address: string; }' is not assignable to type 'Person3'.
// Object literal may only specify known properties, and 'address' does not exist in type 'Person3'.
// 9 address: '杭州'
复制代码
可见,赋值的时候,多一个少一个都不行,变量的属性必须和接口的属性保持一致(前提对接口属性没作处理)。typescript
上面在对接口属性没作任何处理的状况下,赋值的时候,变量属性不能多也不能少。但是有时候咱们仍是但愿有些属性是可选的,一块儿来看看npm
// interfaces4.ts
interface Person4 {
name: string;
age?: number;
}
let pr4: Person4 = {
name: '胖芮'
}
let pr4_1: Person4 = {
name: '胖芮',
address: '杭州'
}
// 0.0.5/interfaces4.ts:12:5 - error TS2322: Type '{ name: string; address: string; }' is not assignable to type 'Person4'.
// Object literal may only specify known properties, and 'address' does not exist in type 'Person4'.
// 12 address: '杭州'
复制代码
可选属性是在属性后面加上 ?
,这个很容易理解(结合正则)。而对于多余属性仍然会报错(不能睁只眼闭只眼,多么正直啊)。json
难道就没别的办法了,看看下面数组
// interfaces5.ts
interface Person5 {
name: string;
age?: number;
[propName: string]: any;
}
let pr5: Person5 = {
name: '胖芮',
isMan: true,
address: '杭州'
}
复制代码
编译后
// build/interfaces5.js
var pr5 = {
name: '胖芮',
isMan: true,
address: '杭州'
};
复制代码
真是天无绝人之路,Typescript 我爱你,你仍是挺有人情味的嘛。
[propName: string]
定义了任意属性,属性 key 类型为 string
;any
,因此 isMan
和 address
都能经过;思考:慢着慢着,任意属性若是设为
string
,可选属性设为number
,二者有冲突么?
// interfaces6.ts
interface Person6 {
name: string;
age?: number;
[propName: string]: string;
}
let pr6: Person6 = {
name: '胖芮',
age: 30,
address: '杭州'
}
// 0.0.5/interfaces6.ts:3:5 - error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
// 3 age?: number;
// 0.0.5/interfaces6.ts:7:5 - error TS2322: Type '{ name: string; age: number; address: string; }' is not assignable to type 'Person6'.
// Property 'age' is incompatible with index signature.
// Type 'number' is not assignable to type 'string'.
// 7 let pr6: Person6 = {
// 0.0.5/interfaces6.ts:15:5 - error TS2322: Type 'string' is not assignable to type 'number'.
// 15 age: '30',
// 0.0.5/interfaces6.ts:3:5
// 3 age?: number;
// The expected type comes from property 'age' which is declared here on type 'Person6'
复制代码
从上面例子的报错及报错缘由中,咱们明白
age
赋值既不能为数字也不能为字符串(到底闹哪样,让不让人活了);age
的 number
类型不是任意属性的 string
的子集,因此 age
怎么赋值都不对;因此,咱们能够将任意属性改成 any
。还有一种解决方式,只不过意义不大。
// interfaces7.ts
interface Person7 {
name: string;
age?: number | string;
[propName: string]: string | number;
}
let pr7: Person7 = {
name: '胖芮',
age: 30,
address: '杭州'
}
let pr7_1: Person7 = {
name: '胖芮',
age: '30',
address: '杭州'
}
复制代码
编译经过,经过变量的赋值,age
可为数字也可为字符串,那咱们用联合类型 number | string
,这里调整了,那任意属性也得调整,也至少得是 string | number
,固然为 any
最好不过。
说完了可选属性和任意属性,再看看另一种场景只读属性。其使用场景是对象的某些字段只在建立时被赋值,后面不可更改。
// interfaces8.ts
interface Person8 {
readonly name: string;
age?: number | string;
[propName: string]: any;
}
let pr8: Person8 = {
name: '胖芮',
age: 30,
address: '杭州'
}
pr8.age = 18; // 永远18岁
pr8.name = '胖芮2代'; // 火影看多了
let pr8_1: Person8 = {
address: '杭州'
}
pr8_1.age = 18;
pr8_1.name = '胖芮3代';
// 0.0.5/interfaces8.ts:14:5 - error TS2540: Cannot assign to 'name' because it is a read-only property.
// 14 pr8.name = '胖芮2代'; // 火影看多了
// 0.0.5/interfaces8.ts:17:5 - error TS2741: Property 'name' is missing in type '{ address: string; }' but required in type 'Person8'.
// 17 let pr8_1: Person8 = {
// 0.0.5/interfaces8.ts:2:14
// 2 readonly name: string;
// 'name' is declared here.
// 0.0.5/interfaces8.ts:22:7 - error TS2540: Cannot assign to 'name' because it is a read-only property.
// 22 pr8_1.name = '胖芮3代';
复制代码
上面例子中,咱们可看出
name
属性前加了关键字 readonly
,意指该属性只读;age
和 name
从新赋值,给 name
赋值这行报错,这是咱们但愿看到的,666;pr8_1
赋值时,可读属性 name
没有被赋值(这个错误咱们容易理解),后面才给 name
赋值,又报错,由于是它是可读属性,哪怕以前给变量赋值时没给它赋值;可见,对只读属性的约束是第一次给只读属性的对象赋值,而不是第一次给只读属性赋值。