前言
TypeScript真香系列的内容将参考中文文档,但是文中的例子基本不会和文档中的例子重复,对于一些地方也会深入研究。另外,文中一些例子的结果都是在代码没有错误后编译为JavaScript得到的。如果想实际看看TypeScript编译为JavaScript的代码,可以访问TypeScript的在线编译地址,动手操作,印象更加深刻。
概念
TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。可以说接口的出现,可以让我们在开发之中发现并避免许多问题的出现,提高我们的开发效率。
接口基础
在面向对象编程中,接口是一种规范的定义,它定义了行为和动作的规范。如下面的例子:
interface IDo {
work:string;
time:number;
}
interface IMan {
age:number;
name:string;
do:IDo;
}
let james: IMan = {
name: 'james',
age: 35,
do: {
work: 'player',
time: 2020
}
}
james.name; //"james"
james.do.work; //"player"
如果我们在james中把name的类型写成数字12,也就是number类型,或者没有写age。那么就会出现错误提示。
可选属性
在我们开发中,接口中的属性有时候也不全都是必要的,在有些条件下存在,有些条件下又是不存在的。
interface IMan {
age?:number;
name:string;
}
let james: IMan = {
name:"james"
}
只读属性
一些对象属性只能在对象刚刚创建的时候修改其值。
interface IMan {
age:number;
readonly name:string;
}
let james: IMan = {
name:"james",
age:35
}
james.name = "mike"; // error: Cannot assign to 'name' because it is a read-only property.
额外的属性检查
在我们能够确定一个对象可能具有某些做为特殊用途使用的额外属性时,最佳的方式是能够添加一个字符串索引签名。
interface IMan {
age:number;
readonly name:string;
[propName: string]: any;
}
let james: IMan = {
name:"james",
age: 35,
work:"player"
}
函数类型
函数也是对象,类似的我们可以用接口表示函数的类型。
interface IFunc {
(x: string, y: string): string;
}
let func: IFunc = function(x: string, y: string){
return x + y;
}
func("1", "!"); // "1!"
对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。
interface IFunc {
(x: string, y: string): string;
}
let func: IFunc = function(a: string, b: string){
return a + b;
}
func("1", "!"); // "1!"
可索引的类型
可用于数组和对象的约束。
interface IMan {
[index:number]:string
}
//数组
let man1: IMan;
man1 = ["james", "wade", "bosh"];
//对象
let man2: IMan;
man2 = {1:"haha", 2:"666"};
console.log(man1); //["james", "wade", "bosh"]
console.log(man2); //{1: "haha", 2: "666"}
类类型
TypeScript也能够用接口来明确的强制一个类去符合某种规定,可以用implements来实现。
interface IMan {
name:string;
play(val:string):void;
}
class IFootballer implements IMan {
name:string
constructor(name:string){
this.name = name
}
play(val:string){
console.log(this.name + '踢'+ val)
}
}
class IBasketballer implements IMan {
name: string
constructor(name:string){
this.name = name
}
play(val:string){
console.log(this.name + '打'+ val)
}
}
var a = new Footballer('武磊')
a.play("足球") //武磊踢足球
var b = new Basketballer ('姚明')
b.play("篮球") //姚明打篮球
继承接口
和我们的类一样,接口之间也可以相互继承。
interface IMan {
name: string;
}
interface IPlayer extends IMan {
types:string
}
class IFootballer implements IPlayer {
name: string;
types: string;
constructor(name:string, types:string){
this.name = name;
this.types = types
}
play(){
console.log(this.name+ "是" + this.types)
}
}
let a = new Footballer("c罗", "足球运动员");
a.play(); //c罗是足球运动员
一个接口也可以继承多个接口,中间用逗号分隔。
interface IMan {
name: string;
}
interface ICity {
city:string;
}
interface IPlayer extends IMan,ICity {
types:string
}
混合类型
我们可以让一个对象同时具有多种类型。
interface ICounter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): ICounter {
let counter = <ICounter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
接口继承类
当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的private和protected成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。
当我们有一个庞大的继承结构时这很有用,但要指出的是我们的代码只在子类拥有特定属性时起作用。 这个子类除了继承至基类外与基类没有任何关系。
class Control {
private state: any;
}
interface ISelectableControl extends IControl {
select(): void;
}
class Button extends Control implements ISelectableControl {
select() { }
}
class TextBox extends Control {
select() { }
}
// 错误:“Image”类型缺少“state”属性。
class Image implements ISelectableControl {
select() { }
}
//error
class Location {
}
参考
https://github.com/zhongsp/Ty...
最后
文中有些地方可能会加入一些自己的理解,若有不准确或错误的地方,欢迎指出~
祝大家新年快乐,阖家辛福!
希望前线的医护人员健健康康,早日打败病毒!
希望大家都健健康康!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。