TypeScript学习摘要(二)——接口

基本使用

  • ts的接口好比一个名字,用来描述对象的类型要求,通过interface 关键字定义

    interface LabelledValue {
      label: string;
    }
    
    // 通过接口定义函数参数类型要求
    function printLabel(labelledObj: LabelledValue) {
      console.log(labelledObj.label);
    }
    
    let myObj = {size: 10, label: "Size 10 Object"};
    printLabel(myObj);
    
  • 直接通过接口定义的属性都是必须的,对于可选属性可通过?: 定义,类似于js中的?.

    interface SquareConfig {
      color: string; // 必传
      width?: number; // 非必传
    }
    function createSquare(config: SquareConfig): {color: string; area: number} {
      let newSquare = {color: "white", area: 100};
      newSquare.color = config.color;
      if (config.width) {
        newSquare.area = config.width * config.width;
      }
      return newSquare;
    }
    
  • 当希望对象的属性不可修改时,可用readonly 关键字设置为只读

    interface Point {
        readonly x: number;
        y: number;
    }
    let p1: Point = { x: 10, y: 20 }; // 初始赋值
    p1.x = 5; // error! x is a read-only property
    p1.y = 30 // ok!
    
  • 数组对象可通过ReadonlyArray设置只读

    // 可将普通数组修改为只读数组
    let a: number[] = [1, 2, 3, 4];
    let ro: ReadonlyArray<number> = a;
    ro[0] = 12; // error!
    ro.push(5); // error!
    // 但只读数组不能通过赋值的方式修改为普通数组
    let a2: number[] = ro // error!
    // 可用断言的方式重新设置为普通数组
    let a3: number[] = ro as number[] // ok
    
  • 最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly

  • 当我们给函数传入接口未定义的额外属性时,ts会报错

    // error: 'other' not expected in type 'SquareConfig'
    let mySquare = createSquare({ other: "demo", color: "white" });
    

    使用断言可以避开额外属性检查

    let mySquare = createSquare({ other: "demo", color: "white" } as SquareConfig);
    

    但是,最佳的方式是在接口上添加一个字符串索引签名

    interface SquareConfig {
        color: string;
        width?: number;
        [propName: string]: any; // 表示除了上面定义的color 和 width, SquareConfig 还可以带有任意数量的字符串属性,这些属性的返回值可以是任意类型
    }
    

    还有一种跳过检查的方式,就是将参数先赋值给另一个变量,通过这种方式不会进行 额外属性的检查

    const tempObj = { other: "demo", color: "white" }
    let mySquare = createSquare(tempObj);
    

函数类型

  • 除了描述带有属性的普通对象外,接口也可以描述函数类型

  • 我们需要给接口定义一个调用签名。 它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。

    interface SearchFunc {
      // 参数类型                         // 返回值类型
      (source: string, subString: string): boolean;
    }
    
  • 调用的时候函数的参数名不需要与接口里定义的名字相匹配,且不需要显式的指定参数类型,因为函数直接赋值给了 SearchFunc类型变量,ts会对参数进行逐个检查并自动判断参数类型和返回值类型

    const testFn:SearchFunc = (src, sub) => {
      console.log(src)
      console.log(sub)
      return true
    }
    

可索引的类型

  • 用于描述那些能够“通过索引得到”的类型,如a[10] ageMap["daniel"]

  • 可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型

    interface StringArray {
      [index: number]: string;
    }
    
    let myArray: StringArray;
    myArray = ["Bob", "Fred"];
    
    let myStr: string = myArray[0];
    
  • TypeScript支持两种索引签名:字符串和数字。 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用 number来索引时,JavaScript会将它转换成string然后再去索引对象。 也就是说用 100(一个number)去索引等同于使用"100"(一个string)去索引,因此两者需要保持一致

  • 索引签名也可以设置为只读

    interface ReadonlyStringArray {
        readonly [index: number]: string;
    }
    let myArray: ReadonlyStringArray = ["Alice", "Bob"];
    myArray[2] = "Mallory"; // error!
    

类类型

  • 与C#或Java里接口的基本作用一样,TypeScript也能够用它来明确的强制一个类去符合某种契约

  • 接口描述了类的公共部分,而不是公共和私有两部分。 它不会帮你检查类是否具有某些私有成员

    interface ClockInterface {
        currentTime: Date;
        setTime(d: Date);
    }
    
    class Clock implements ClockInterface {
        currentTime: Date;
        setTime(d: Date) {
            this.currentTime = d;
        }
        constructor(h: number, m: number) { }
    }
    
  • 类是具有两个类型的:静态部分的类型和实例的类型;

  • 当一个类实现了一个接口时,只对其实例部分进行类型检查。 constructor存在于类的静态部分,所以不在检查的范围内

接口继承

  • 接口可以相互继承复用

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

混合类型

  • 一个对象可以同时做为函数和对象使用,并带有额外的属性

    interface Counter {
        (start: number): string;
        interval: number;
        reset(): void;
    }
    
    function getCounter(): Counter {
        let counter = <Counter>function (start: number) { };
        counter.interval = 123;
        counter.reset = function () { };
        return counter;
    }
    
    let c = getCounter();
    c(10);
    c.reset();
    c.interval = 5.0;
    

接口继承类

这一节还不太理解,节选ts中文文档原文

  • 当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的private和protected成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。

  • 当你有一个庞大的继承结构时这很有用,但要指出的是你的代码只在子类拥有特定属性时起作用。 这个子类除了继承至基类外与基类没有任何关系。 例:

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// 错误:“Image”类型缺少“state”属性。
class Image implements SelectableControl {
    select() { }
}

class Location {

}
  • 在上面的例子里,SelectableControl包含了Control的所有成员,包括私有成员state。 因为 state是私有成员,所以只能够是Control的子类们才能实现SelectableControl接口。 因为只有 Control的子类才能够拥有一个声明于Control的私有成员state,这对私有成员的兼容性是必需的。
  • Control类内部,是允许通过SelectableControl的实例来访问私有成员state的。 实际上, SelectableControl接口和拥有select方法的Control类是一样的。 ButtonTextBox类是SelectableControl的子类(因为它们都继承自Control并有select方法),但ImageLocation类并不是这样的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容