TS學(xué)習(xí)筆記(二):接口

在面向?qū)ο笳Z言中,接口(Interfaces)是一個很重要的概念,它是對行為的抽象,而具體如何行動需要由類(classes)去實現(xiàn)(implements),TypeScript 中的接口除了可用于對類的一部分行為進行抽象以外,也常用于對對象的形狀(Shape)進行描述。

接口初探

類型檢查器不會去檢查屬性的順序,只要相應(yīng)的屬性存在并且類型也是對的就可以。

interface IPerson{
  name: string;
  age: number
}
function say(person: IPerson): void {
  console.log(`my name is ${person.name}, and age is ${person.age}`)
}
let me = {
  name: 'funlee',
  age: 18
}
say(me); // my name is funlee, and age is 18

可選屬性

定義可選屬性的接口,只需在可選屬性名字的定義后面加一個 ? 符號

interface IPerson {
  name: string;
  age: number;
  love?: string
}
function say(person: IPerson): void {
  if(person.hasOwnProperty('love')) {
    console.log(`my name is ${person.name}, my age is ${person.age}, and I love ${person.love}`);
  } else {
    console.log(`my name is ${person.name}, and age is ${person.age}`);
  }
}
let me = {
  name: 'funlee',
  age: 18,
  love: 'TS'
}
let you = {
  name: 'Jack',
  age: 18
}
say(me); // my name is funlee, my age is 18, and I love TS
say(you) // my name is Jack, and age is 18

只讀屬性

定義只讀屬性的接口,只需在只讀屬性名前加 readonly

interface IPerson {
  readonly name: string;
  age: number;
  love?: string
}
let me: IPerson = {
  name: 'funlee',
  age: 18
}
me.name = 'new name'; // error!

額外的屬性檢查

當(dāng)一個對象字面量里聲明了接口中不存在的屬性時,會報不存在錯誤,即使該屬性已設(shè)置為可選屬性,因為該對象字面量會被特殊對待而且會經(jīng)過額外屬性檢查,繞開額外屬性檢查的方法如下:

  • 使用類型斷言
  • 添加一個字符串索引簽名,前提是你能夠確定這個對象可能具有某些做為特殊用途使用的額外屬性
  • 將該對象賦值給另一個變量
// 錯誤寫法,會進行額外檢查
interface IPerson {
  name: string;
  age?: number;
}
let me: IPerson = {
  name: 'funlee',
  love: 'TS'
}

// 方法一:類型斷言
interface IPerson {
  name: string;
  age?: number;
}
let me = {
  name: 'funlee',
  love: 'TS'
} as IPerson

// 方法二:字符串索引簽名
interface IPerson {
  name: string;
  age?: number;
  [propName: string]: any;
}
let me: IPerson = {
  name: 'funlee',
  love: 'TS'
}

// 方法三:賦值給另一個變量
interface IPerson {
  name: string;
  age?: number;
}
let me = {
  name: 'funlee',
  love: 'TS'
}
let you: IPerson = me;

函數(shù)類型

接口可以描述函數(shù)類型,它定義了函數(shù)的參數(shù)列表和返回值類型,參數(shù)列表里的每個參數(shù)都需要名字和類型,函數(shù)的參數(shù)名不需要與接口里定義的名字相匹配,只需要類型兼容就可以了。

let getArea: (width: number, height: number) => number = (w: number, h: number): number =>{
  return w * h;
}
console.log(getArea(5, 6)) // 30

可索引的類型

接口可以描述那些能夠通過索引得到的類型,可索引類型具有一個索引簽名,它描述了對象索引的類型,還有相應(yīng)的索引值類型,索引簽名支持兩種類型:number 和 string,但是由于 number 實際上會被轉(zhuǎn)化為 string 類型(根據(jù)對象 key 的性質(zhì)),所以需要遵守:number 索引的返回值類型是 string 索引的返回值類型的子類型。

interface IPerson {
  [index: string]: string;
}
let me: IPerson = {love: 'TS'}
me.name = 'funlee';
me.age = 18; // error

如果 interface 里還聲明了一個和索引簽名索引返回值類型不匹配的屬性,會報錯

interface ITest {
  [index: string]: string;
  name: string;
  age: 18; // 報錯,因為返回值類型是number,不符合string類型
}

還可以聲明一個 readonly 的索引簽名

interface IPerson {
  readonly [index: string]: string;
}
let p: IPerson = {name: 'funlee'};
p.love = 'TS'; // error

類類型

typescript 里也允許像 Java、C# 那樣,讓一個 class 去實現(xiàn)一個 interface;但是需要注意的是,接口描述的是類的公共部分,而不是公共和私有兩部分,所以不會檢查類是否具有某些私有成員。

interface ISome {
  prop: string // 描述一個屬性
  method(paramA: string, paramB: number) // 描述一個方法
}
class A implements ISome {
  prop: 'propValue'
  method(a: string, b: number) {
    // ...
  }
  constructor(paramA: number){
    // ...
  }
}

靜態(tài)部分與實例部分

首先看一個示例:用構(gòu)造器簽名定義一個接口,并試圖實現(xiàn)這個接口:

interface Person {
  new(name: string)
}
class People implements Person {
  constructor(name: string) {
    // ...
  }
}
// 報錯:no match for the signature 'new (name: string): any'.

這是因為:當(dāng)類實現(xiàn)一個接口時,只對實例部分進行類型檢查,而constructor存在于靜態(tài)部分,所以不在檢查的范圍內(nèi)。
所以做法如下:

// 針對類構(gòu)造函數(shù)的接口
interface CPerson {
  new(name: string)
}
// 針對類的接口
interface IPerson {
  name: string
  age: number
}
function create(c: CPerson, name: string): IPerson {
  return new c(name)
}
class People implements IPerson {
  name: string
  age: number
}
let p = create(People, 'funlee') // 可以

繼承接口

和類一樣,接口也可以相互繼承,如:

interface Shape {
  color: string;
}
interface Square extends Shape {
  sideLength: number;
}
const square = <Square>{};
square.color = 'blue';
square.sideLength = 10;

同時,一個接口也可以繼承多個接口,創(chuàng)建出多個接口的合成接口,如:

interface Shape {
  color: string;
}
interface PenStroke {
  penWidth: number;
}
interface Square extends Shape, PenStroke {
  sideLength
}
const square = <Square>{};
square.color = 'blue';
square.sideLength = 10;
square.penWidth = 5.0;

混合類型

允許讓一個對象同時作為函數(shù)和對象使用,并帶有額外的屬性,如:

interface MixedDemo {
  (str: string): void;
  defaultStr: string;
}

function foo(): MixedDemo {
  let x = <MixedDemo>function(str: string){
    console.log(str)
  }
  x.defaultStr = 'Hello, world'
  return x
}

let c = foo();
c('This is a function') // 'This is a function'
console.log(c.defaultStr) // 'Hello, world'

接口繼承類

接口可以繼承自一個類,從而像聲明了所有類中存在的成員,并且private和protected成員也會被繼承,這意味著:只有類自己或子類能夠?qū)崿F(xiàn)該接口,例子如:

class A {
  protected propA: string
}
interface I extends A {
  method(): void
}

// 下面這種做法會報錯
class C implements A {
  // 因為propA是類A的保護成員,只有自身和子類可實現(xiàn)
  // 但類C不是A的子類
  protected propA: string
  method() {}
}

// 下面這種做法則是允許的
class C extends A implements A {
  protected propA: string
  method() {}
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 12,405評論 6 13
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,654評論 1 32
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 3,143評論 2 9
  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當(dāng)在唯一索引所對應(yīng)的列上鍵入重復(fù)值時,會觸發(fā)此異常。 O...
    我想起個好名字閱讀 5,967評論 0 9
  • 淅淅瀝瀝的小雨伴著那秋的腳步來臨了。喜歡這樣的雨––毛毛細(xì)雨,潤物細(xì)無聲。 毛毛細(xì)雨,打濕在你的頭上、身上、心上;...
    甜甜的小可閱讀 277評論 0 2

友情鏈接更多精彩內(nèi)容