接口 interface
接口,就是约定、限制的意思。
说白了,就是如果你实现了这个接口,你就必须得是这个样子,你不能是别的。你要是别的,那我就不承认你是我接口的一员。
我们先来看一个例子:
A 就是我们实现的一个接口。它必须得是一个对象,并且必须有 2 个属性 x 和 y。
并且 x 和 y 的类型必须是 number。
然后我们在添加一个接口 B:
a.x 和 a.y 不会报错。但 a.z 会报错。
你必须得用它们两个的公有属性,都有的才行。
所以,接口,你可以理解为一种必须遵守的规范。
看到这里,是不是觉得有些眼熟?这不就是我们前面说的 type 吗?只不过换了个关键字而已。
其实 interface 和 type 在很大程度上面是有交界的,可以互换。
我们再来看一个例子:
这里需要注意下,它之所以不会报错。是因为数组也是对象。
所以我们还得继续去规定:
那么,如果我们将 interface 换成 type 呢?
可以看到,一样不会报错。
其实 interface 根本就不是当类型用的,它真正的用法在于,需要我们把它用来实现。
比如说现在有一个需求,我有一个数据,我要求它是可以转成字符串,然后再转回来的。
所以它里面应该会有 2 个方法:
一个 tostring 方法,没有任何参数,返回一个字符串出来。
一个 fromstring 方法,接收一个字符串作为参数,返回值是空。
然后我们可以用 implements 这个关键字实现一个接口。
这样写,会报错。
这是因为我们并没有 tostring 和 fromstring 两个方法。
加上 tostring 和 fromstring 两个方法后,就不会报错了。
如果你实现了某个接口,那么你要做的就是:
必须得实现这个接口当中规定了的那些方法。这就是接口的含义。
那么接口到底能干什么呢?
interface 它是一种规范,这个规范的意义就在于,你如果实现了我这个东西,你就必须得有相应的动作。
比如说,你就得提供 tostring 和 fromstring 这两个东西,它们一定得有。
那它怎么使用呢?
比如我们现在有一个函数 sendToServer,它所接受的参数,只能有一种。
就是必须得实现了 serializeable 接口的东西。
可以看到,这样是没问题的。
因为我传入的参数是 UserData 的实例。一切都符合要求。
那么如果函数 sendToServer 的参数,我传入一个没有实现 serializeable 接口的对象呢?
这时候就会报错:说 UserData2 并没有实现这个 serializeable 接口。
那么我们的目的是什么呢?
我们平时调试 js,是让程序跑起来之后,这里点点,那里输入点什么。你得测试,不停的点,不停的去找问题。
但是这种方法可能会有遗漏,而且时间和成本消耗也比较大。
但是如果我们不用程序真的跑起来,只是编译期间就能找到这个问题,那不是最好的吗?
ts 给我们提供的,就是这种方法。
然后我们通过上面的例子,可以看到 implements 的用法其实和 extends 是有点像的。
那么它们之间又有什么区别呢?
implements 是实现一个接口,并且可以同时实现多个接口。
写法也比较简单,写在后面,用逗号隔开就行:
extends 它是用来继承的,并且只能继承一个类。
所以,如果我有很多东西想要去规范,那么我们用 implements 更合适。
接下来,我们来看下 ts 里面最受欢迎之一的,泛型。
泛,指的是宽泛。意思是我不限定这个类型,你可以是任何类型。
看到这里,是不是也觉得和前面一个东西特别像?any。
但是这里需要注意的是,不要将泛型和 any 搞混了。
我们先来看下泛型的基本用法:
class Calc<T> {
a: T
b: T
}
上面的 <T> 就是泛型。
T 是一个类型,意味着你可以在里面用。a, b 都是 T 类型。
所以,说白了,泛型,就相当于把类型当参数传进去。
然后我们来看个例子:
可以看到,左边的 obj.a 和 obj.b 都是 number 类型是没有问题的。
而右边,我们将 obj.b 赋值成字符串,就会报错了。
所以,在 new Calc<number> 这个时候,我们就把它的类型限制住了。
这个和 any 是有区别的,any 是不限制类型。
泛型虽然说可以变成任何类型,但还是有限制的,你只能在我这个圈里面选,你不能选别的。
泛型可以用联合类型:
然后我们再来看一个例子:
可以看到,repeat<number> 和 Array<number> 有点像。
实际上在 ts 里面来说,数组 Array 就是一个泛型。
平时的写法:
let arr = [12, 5]
稍微完善一点:
let arr:number[] = [12, 5]
完整写法:
let arr:Array<number> = new Array()
或
let arr:Array<number> = new Array<number>()
其实我们一般都是用的简写:let arr:number[] = [12, 5]。
泛型类:
我们先 add 了一个数字类型 12,又 add 了一个字符串类型 'abc'。
按照类型推测,这时候是应该报错的。但是程序却没有报错。为什么呢?
这是因为 ts 现在推测不出来它到底是什么类型了,这个比较复杂。
ts 能推测的,就是在初始化阶段。再往后,就不行了。
所以我们可以在初始化的时候,手动的来声明一下,规定它这个数组,只能存某一个类型。
这个时候,它就会报错了。