TypeScript interface

typescript之旅

1.TypeScript-Basic
2.TypeScript interface
3.Typescript-module(1)
4.TypeScript Modules(2)
5.Typescript tsconfig
6.TypeScript Functions
7.Typescript Class

Interfaces

今天来说说接口,首先说明如果你是java程序员,请一定忘记interface,此处的接口和彼处接口完全不是一个思想。

首先来一个最简单的接口
字面量接口

不使用interface关键字就定义了一个接口

function printLabel(labelledObj: {label: string}) {
  console.log(labelledObj.label);
}

var myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

上面没有interface关键字,哪个是接口呢?
{label: string}
你说这个玩意不是变量labelledObj的类型吗?我知道typescript说白了就是js的类型系统,前面也介绍了如:Boolean,Number,String,Array,Enum,Any,Void
其实接口就是定义了一个对象有哪些属性,并且属性值是什么类型

好了,来个高级点的(interface关键词上场)

interface LabelledValue {
  label: string;
}

function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}

let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

OK,懂了吗,自定义类型
啊,太棒了,以后再也不用判断某个属性是否un

可选属性

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): {color: string; area: number} {
  let newSquare = {color: "white", area: 100};
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

let mySquare = createSquare({color: "black"});

好处:

  1. 预定义属性

  2. 编译器可以捕获对不存在属性引用的错误

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  let newSquare = {color: "white", area: 100};
  if (config.color) {
    // Error: Property 'collor' does not exist on type 'SquareConfig'
    newSquare.color = config.collor;  // Type-checker can catch the mistyped name here
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

let mySquare = createSquare({color: "black"});

对于这个错误例子,我们引出了下一节

额外的属性检查

上面的例子也许有人会争辩(js的忠实用户者),js对象是灵活的,你现在搞得跟JAVA一样了!
反对~反对!

是的,typescript对对象字面量会特殊对待(即经过额外属性检查),当将他们赋值给变量或作为函数参数时。
因此你会得到一个错误

// error: 'colour' not expected in type 'SquareConfig'    
let mySquare = createSquare({ colour: "red", width: 100 });

解决办法
1.类型断言法(类似于c语言的强制类型转换,告诉编译器,我就要转,别给我报错啊!)

let mySquare = createSquare({ colour: "red", width: 100 } as SquareConfig);

2.钻空子法(我们了解编译器的检查方式了,我绕过去就行了)

let squareOptions = { colour: "red", width: 100 };
let mySquare = createSquare(squareOptions);

函数类型

首先我们要肯定interface使我们定义了各种对象外形。
现在我们把string,number,boolean,object类型都定义了,完工了!
且慢,等等~对于其他语言是够了,但js~~~
你想,js的函数是一等公民,你能忘了它~

当当当当,来了!

interface SearchFunc {
  (source: string, subString: string): boolean;
}

demo:

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
  let result = source.search(subString);
  if (result == -1) {
    return false;
  }
  else {
    return true;
  }
}

好处:
1.检查参数类型
2.返回值类型检查,上例,如果你返回字符串或数字,就报错了

数组类型

数组可以想象成一种特殊函数,只有一个参数(index)的函数

interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

OK,没有问题吗?index只能是number类型吗?我还知道一种叫关联数组的玩意(index是string)

我们经常这样用obj.property和obj[“property”]

  1. 目前支持两种index类型:number,string

  2. 可以同时使用两种索引类型

  3. 限制:数字索引返回值的类型必须是字符串索引返回值的类型的子类型

demo

interface NumberDictionary {
  [index: string]: number;
  length: number;    // 可以,length是number类型
  name: string       // 错误,`name`的类型不是索引类型的子类型
}

类类型(肩负重任的inteface关键字)

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

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) { }
}
interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}

class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}
  • 接口描述了类的公共部分,而不是公共和私有两部分。 它不会帮你检查类是否具有某些私有成员。

类静态部分与实例部分的区别

  • 这部分比较冷~

  • 类是具有两个类型的:静态部分的类型和实例的类型

  • 构造函数是静态部分,而一个类去实现一个带有构造器签名的接口时会报错

interface ClockConstructor {
    new (hour: number, minute: number);
}

class Clock implements ClockConstructor {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

那如何才能使用接口对构造器类型检查呢

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}
class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

拓展接口

  • 和类一样,接口也可以相互扩展。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;

多继承

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;

混合类型

  • 还是JS的特殊语法

function demo(){
    ...
}

demo.attr1 = '1';
demo.fun = function(){
    ...
}

这是什么情况,函数类型,对象类型,额,混合类型

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;

接口继承类

  • 还不是很明白

    原文作者:Sike
    原文地址: https://segmentfault.com/a/1190000004619949
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞