该文章是 TypeScript 系列文章第三篇,该系列会带大家从基础开始学习直到在项目中使用。一周更新 2 篇左右,有任何问题留言提问,我都会一一解答。本篇文章介绍的是接口和泛型的知识。

接口

对于接口来说,你可以把它想成是 type 的加强版。也是用来声明对象类型的,但是用法更复杂。对于接口来说,他只存在于 TS 中,不会编译成 JS。

语法
interface Persons { 
    name: string
    age: number
}
let p: Persons

这就是一个接口的最基语法,定义了对象里必须存在一个 key 为 name 且值为字符串。

但是有一点需要注意,如果你使用字面量的方式传入 Persons 类型的变量会有点不一样。

function say(p: Persons) {
    console.log(p.name)
}
let p = { name: 'yck' }
say(p) // success
say({ name: 'yck' }) //error

你会发现在传入变量的编译通过了,但是传入字面量的时候编辑器就报错了,说必须传入 age 属性,这里你有几种办法可以解决。

第一种方式你可以使用类型断言 as

say({ name: 'yck' } as Person)

第二种方式你可以让属性可选 ?

// 问号表明这个属性可有可无
interface Persons { 
    name?: string
    age?: number
}

第三种方式你可以使用可计算属性特性,这个和 ES6 的特性没什么区别

interface Persons { 
    name: string
    age: number
    // key 随便写
    [key: string]: any
}
继承

对于接口来说,接口可以继承自接口也可以继承自类。接口也可以被类继承。

// 接口 Mine 中除了拥有 job 属性
// 同时也有了 Persons 中的属性
// 这个和类继承概念是一样的
interface Mine extends Persons { 
    job: string
}
class People {
    job: string
}
// 和上面一样,也有了 People 中的属性
interface My extends People { 
    name: string
}
// 类如果继承了接口
// 那么在类中必须声明接口中的必选属性
class My extends People {
    job: string
    // name 必须声明
    name: string
}

关于接口的知识就讲到这里。对于接口来说,用处就是用来定义对象类型的。

泛型

我们来考虑一个场景,我有一个需要参数的函数,但是我不知道参数会是类型,并且函数会讲这个参数返回出来。我拿到返回值还要进行一些操作。那么首先你肯定会考虑到使用 any 类型。这个答案肯定是没错的,但是首先在 TS 中我们应该尽量少的使用 any 类型,再者,我们后续还要对于返回值操作,但是这时候编辑器并不知道返回值的类型,所以他不能给我很好的一个代码提示。

function say(name: any) {
    return name
}
say('yck').length
say(123).length

这时候泛型可以很好的帮助我们

// <>代表你使用了泛型,尖括号中的
// T 是自己随意命名的,在某些地方你
// 可以直接传入类型 Array<string>
// 并且在尖括号中如果想声明多个类型也是可以的
// <T, U>
// 声明好泛型后,你就可以像使用别的类型
// 一样使用他们
function say<T>(name: T) {
    return name
}
// 当我们传入字符串的时候
// 代码会自动推断出返回值类型
// 也是字符串,也会有更精确的代码提示
say('yck').length

对于泛型来说,我们也可以规定他们的类型范围

// 这说明类型 T 必须是字符串或者数字
function say<T extends string | number>(age: T) {
    return age
}

现在我们来将这讲的内容一起实践下

interface Type {
    name: string
    age: number
}
class Mine<T extends Type> {
    obj: T
    constructor(value: T) {
        this.obj = value
    }
}
// 你会发现这里在传参的时候
// 会直接给你 Key 的代码提示
let m = new Mine({name: 'yck', age: 25})
m.obj.age

所以对于泛型来说,第一个好处是让我们的代码能够更好的复用,更好的适用于各种类型。第二个好处就是增加了开发速度,原本需要手打的属性现在都有提示了。