TypeScript接口的使用(七)

1. 接口的声明

在前面我们通过type可以用来声明一个对象类型:

type Point = {
  x: number
  y: number
}

对象的另外一种声明方式就是通过接口来声明:

interface Point = {
  x: number
  y: number
}

接口类型也可以定义可选类型和只读属性,只读属性指我们再初始化之后,这个值是不可以被修改的

// 通过类型(type)别名来声明对象类型
// type InfoType = {name: string, age: number}

// 另外一种方式声明对象类型: 接口interface
// 在其中可以定义可选类型
// 也可以定义只读属性
interface IInfoType {
  readonly name: string
  age: number
  friend?: {
    name: string
  }
}

const info: IInfoType = {
  name: "why",
  age: 18,
  friend: {
    name: "kobe"
  }
}

console.log(info.friend?.name)
console.log(info.name)
// info.name = "123"
info.age = 20


2. 索引类型

// 通过interface来定义索引类型
interface IndexLanguage {
  [index: number]: string
}

const frontLanguage: IndexLanguage = {
  0: "HTML",
  1: "CSS",
  2: "JavaScript",
  3: "Vue"
}


interface ILanguageYear {
  [name: string]: number
}

const languageYear: ILanguageYear = {
  "C": 1972,
  "Java": 1995,
  "JavaScript": 1996,
  "TypeScript": 2014
}


3. 函数类型

前面我们都是通过interface来定义对象中普通的属性和方法的,实际上它也可以用来定义函数类型:
用接口定义函数类型


image.png
// type CalcFn = (n1: number, n2: number) => number
// 可调用的接口
interface CalcFn {
  (n1: number, n2: number): number
}

function calc(num1: number, num2: number, calcFn: CalcFn) {
  return calcFn(num1, num2)
}

const add: CalcFn = (num1, num2) => {
  return num1 + num2
}

calc(20, 30, add)


4. 接口继承

接口和类一样是可以进行继承的,也是使用extends关键字:
并且我们会发现,接口是支持多继承的(类不支持多继承)

interface ISwim {
  swimming: () => void;
}

interface IFly {
  flying: () => void;
}

interface IAction extends ISwim, IFly {}
//支持多继承

const action: IAction = {
  swimming() {},
  flying() {},
  //里面必须有这两个方法
};

image.png

5.交叉类型

image.png

6.交叉类型的应用

image.png
// 一种组合类型的方式: 联合类型
type WhyType = number | string;
type Direction = "left" | "right" | "center";
/* ,联合类型的话是把我们多个这个值,
多个我们的类型,多个类型跟他联合在一起,到时候的话,你取里面的任何,一个类型都可以 */

// 另一种组件类型的方式: 交叉类型
type WType = number & string;

interface ISwim {
  swimming: () => void;
}

interface IFly {
  flying: () => void;
}

type MyType1 = ISwim | IFly;
type MyType2 = ISwim & IFly;

const obj1: MyType1 = {
  flying() {},
};

const obj2: MyType2 = {
  swimming() {},
  flying() {},
};

export {};

两个接口他们的组合的时候就有两种方式了,第一种方式的话是定义一个新的接口,然后让他们继承自我原来的这两个接口,那么这个接口里面就相当于把前面这两个就给他组合在一起了,另外一种方式,交叉类型,他也是可以把我们两个对象类型,两个对象类型跟他结合在一起,结合在一起之后的话,生成一个新的类型.

7.接口的实现

1.接口作为标识符的使用

interface Iswim {
  swimming: () => void;
}

interface IEat {
  eating: () => void;
}

//这两个接口可以作为类型,比如在定义变量的时候
const a: Iswim = {
  swimming() {},
}; //接口作为标识符类型

function foo(swim: Iswim) {
  //传入的这个对象必须满足这个接口
}
foo({ swimming() {} });
  1. 类可以作为接口
interface Iswim {
  swimming: () => void;
}

interface IEat {
  eating: () => void;
}
// 类实现接口
class Animal {}

//类Fish除了可以继承Animal,也可以实现接口
//但是继承的化只能实现单继承
class Fish extends Animal implements ISwim, IEat {
  swimming() {
    console.log("Fish Swmming");
  }

  eating() {
    console.log("Fish Eating");
  }
  //因为实现了两个接口所以里面必须有swiming和eating
  /* 
  使用类实现接口的化,编写一一些公共的公共的API的话,在很多的情况下都可以调用的,对于可复用的一些API的时候,它就变得更加的灵活。那么我们就可以面向接口进行编程。
  */
}

//// 编写一些公共的API: 面向接口编程
//function swimAction(swimable: Fish {
//  swimable.swimming();
//}
swimAction(new Fish());
//这么写的话,这个函数就不具备通用性,因为这个参数我们就只能传Fish类型的一个对象。
//如果我们想swimAction({swimming: function() {}})是不可以的。只能new一个Fish对象

//这个时候我们就可以面向接口编程
function swimAction(swimable: ISwim) {
  swimable.swimming()
}
// 1.所有实现了接口的类对应的对象, 都是可以传入
swimAction(new Fish())
//如果Person也实现了 ISwim
class Person implements ISwim {
  swimming() {
    console.log("Person Swimming")
  }
}
swimAction(new Person())
swimAction({swimming: function() {}})
/* 就意味着只要是有一个类,它实现了这个接口,到时候的话,它都是可以调动我公共的这个API的,那么我在编辑这个公共API的时候,我这里最好就是面向接口编程的 
面向接口编程的话,就让我编写的这个API他更加具备通用性啦,在很多很多地方都可以被别人调用,只要你实现了我的这个接口,甚至是我们普通的对象字面量,你只要也是符合我接口对应的类型的,你也是可以传到我们这个里面去的,可以转到这个里面去,所以这个的话就叫做面向接口编程
*/

export {};

8.interface和type区别

image.png
interface IFoo {
  name: string;
}
interface IFoo {
  age: number;
}
/* interface允许定义两个名字相同的接口,意味着会把两个接口的内容合并在一起,相当于
interface Ifoo {
  ame: string
  age: number
}
 */
const foo: IFoo = {
  name: "why",
  age: 18,
};

export {};
// document.getElementById("app") as HTMLDivElement
/* 
刚才我们看到的Windows类型,包括document这些类型它来自哪里呢,这些类型来自于我们在安装typescript的时候,它会默认帮助我们安装一些lib的库,
那安装的这些库里面,它就默认有帮助我们定义很多的类型,
包括比如说这个javascript里面内置的一些类型项,Math,Data这些类型,包括这些内置类型,
也包括dom的一些类型的API的话,
Winodw类型,HTMLDivElement类型等
06:01
*/
//window这个类型没有age这个属性,我们如果想有age这个属性的化
interface Window {
  age: number;
}
//这时候不能覆盖以前的Window,而是合并
window.age = 19;
console.log(window.age);

//type根本不允许定义两个相同的类型
// type IBar = {
//   name: string
//   age: number
// }

// type IBar = {
// }



9.字面量赋值

interface IPerson {
  name: string;
  age: number;
  height: number;
}

const info: IPerson = {
  name: "why",
  age: 18,
  height: 1.88,
  //address: "广州市", //不能添加这个属性,因为IPerson没有定义
};


怎么让他不报错呢

interface IPerson {
  name: string;
  age: number;
  height: number;
}

const info = {
  name: "why",
  age: 18,
  height: 1.88,
  address: "广州市",
}; //info会做类型推导,推导出来
/*  
const info: {
    name: string;
    age: number;
    height: number;
    address: string;
}

*/

const p: IPerson = info;
/* 
这个时候把info类型和IPerson类型是冲突的,因为多了个address
ts主要做类型检测,类型检测通过,你这个代码就没有问题
fressness擦除
当把info这个引用类型赋值给p的时候,他会把我们对应某一个属性给它擦除掉,擦出掉之后,也就是address,如果依然是满足你这里的这个类型的情况下,也就是 IPerson ,因为我们这三个是不是依然是满足的,依然是满足的情况下,就是可以赋值的。如果info里面没有age,你再把这个address擦掉之后,你是少一个的,少一个是不行的,同学们就是擦除掉那些多余的,擦掉那些多余的之后,
我依然是符合你这类型的,他是允许我们这么赋值的,它允许这么赋值
*/

console.log(info);
console.log(p);
/* { name: 'why', age: 18, height: 1.88, address: '广州市' }
{ name: 'why', age: 18, height: 1.88, address: '广州市' } */
export {};


这是因为TypeScript在字面量直接赋值的过程中,为了进行类型推导会进行严格的类型限制。
但是之后如果我们是将一个 变量标识符 赋值给其他的变量时,会进行freshness擦除操作。

应用

interface IPerson {
  name: string;
  age: number;
  height: number;
}

function printInfo(person: IPerson) {
  console.log(person);
  // console.log(person.address);不可以使用address,因为对于类型检测来说,,人家认为你这个person里面只有三个属性,,在这里取address的时候,在类型检测这一步他是过不去的,但是可以直接打印所有
}

// 代码会报错
// printInfo({
//   name: "why",
//   age: 18,
//   height: 1.88,
//   address: "广州市"
// })

const info = {
  name: "why",
  age: 18,
  height: 1.88,
  address: "广州市",
};

printInfo(info);
//{ name: 'why', age: 18, height: 1.88, address: '广州市' }
export {};

10.TypeScript枚举类型

image.png
//,其实枚举类型就是定义一组常量,并且给他放到我们对应的一种数据类型里面
// type Direction = "left" | "Right" | "Top" | "Bottom"

enum Direction {
  LEFT,
  RIGHT,
  TOP,
  BOTTOM,
} //代码阅读性强
/* 
看起来这些东西是我们的一些标识的一些常量,但是其实本质上他们是一些数字常量,也就第一个的话其实是一个零,然后第二个的话是一个一,第三个的话是一个二,然后第四个的话就是一个三,它内部是由我们这里这么一些数字的值的,只不过这些值你不需要去写,你不写的时候,他们默认也是有的,但是能改变这里这些东西的值
enum Direction {
  LEFT = 0,
  RIGH = 1,
  TOP = 2,
  BOTTOM = 3,
} 默认

enum Direction {
  LEFT = 100,
  RIGH = 200,
  TOP = 300,
  BOTTOM = 400,
}
enum Direction {
  LEFT = 100,
  RIGH ,//101
  TOP ,//102
  BOTTOM,//103
}
*/
function turnDirection(direction: Direction) {
  console.log(direction);
  switch (direction) {
    case Direction.LEFT:
      console.log("改变角色的方向向左");
      break;
    case Direction.RIGHT:
      console.log("改变角色的方向向右");
      break;
    case Direction.TOP:
      console.log("改变角色的方向向上");
      break;
    case Direction.BOTTOM:
      console.log("改变角色的方向向下");
      break; //如果少些一个case的化,代码会报错。因为default用了never类型
    default:
      const foo: never = direction;
      break;
  }
}

turnDirection(Direction.LEFT);
turnDirection(Direction.RIGHT);
turnDirection(Direction.TOP);
turnDirection(Direction.BOTTOM);

export {};
/* 
0
改变角色的方向向左
1
改变角色的方向向右
2
改变角色的方向向上
3
改变角色的方向向下
*/

11.枚举类型的值

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

推荐阅读更多精彩内容