Typescript 對象類型-接口

新的一天,打卡簽到。按照在 Typescript 類型推論 裏的約定,咱們將文件 notes/package.jsonversion 改成 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,因此 isManaddress 都能經過;

思考:慢着慢着,任意屬性若是設爲 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 賦值既不能爲數字也不能爲字符串(到底鬧哪樣,讓不讓人活了);
  • agenumber 類型不是任意屬性的 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,意指該屬性只讀;
  • 變量賦值後,給變量的 agename 從新賦值,給 name 賦值這行報錯,這是咱們但願看到的,666;
  • 對變量 pr8_1 賦值時,可讀屬性 name 沒有被賦值(這個錯誤咱們容易理解),後面纔給 name 賦值,又報錯,由於是它是可讀屬性,哪怕以前給變量賦值時沒給它賦值;

可見,對只讀屬性的約束是第一次給只讀屬性的對象賦值,而不是第一次給只讀屬性賦值

本次代碼 Github

你能夠...

上一篇:Typescript 類型斷言

下一篇:Typescript 數組類型

目錄:Typescript 小書之入門篇

相關文章
相關標籤/搜索