1.接口
在前面我们通过type可以用来声明一个对象类型:
type Point = {
x: number
y: number
}
对象的另外一种声明方式就是通过接口来声明
interface Point {
x: number
y: number
}
1.1:可选属性
接口中我们也可以定义可选属性
interface Person {
name: string
age?: number
friend?: {
name:string
}
}
const person: Person = {
name:"xiaobai",
age: 18,
friend: {
name:"kobe"
}
}
console.log(person.name)
console.log(person.friend?.name)
1.2:只读属性
意味着我们再初始化之后,这个值是不可以被修改的
interface Person {
readonly name: string
age?: number
readonly friend?: {
name:string
}
}
const person: Person = {
name:"xiaobai",
age: 18,
friend: {
name:"kobe"
}
}
person.name = "xxx" //不可以设置
person.friend = {}//不可以设置
//下面的代码可以执行
if(person.friend){
person.friend.name = "123"
}
1.3:索引类型
interface FrontLanguage {
[index: number]: string
}
const frontend: FrontLanguage = {
1:"HTML",
2:"CSS",
3:"JavaScript"
}
1.4:函数类型(但是一般建议使用type)
前面我们都是通过interface来定义对象中普通的属性和方法的,实际上它也可以用来定义函数类型
interface CalcFunc {
(num1: number,num2: number): number
}
const add: CalcFunc = (num1,num2) => {
return num1 + num2
}
1.5:接口继承(多继承)
使用extends关键字
接口是支持多继承的(类不支持多继承)
interface Person {
name: string
eating: () => void
}
interface Animal {
running: () => void
}
interface Student extends Person,Animal {
sno: number
}
const stu: Student = {
sno: 110,
name: "xiaobai",
eating: function() {},
running: function() {},
}
1.6:接口对于类的实现
接口定义后,也是可以被类实现的:
如果被一个类实现,那么在之后需要传入接口的地方,都可以将这个类传入;
这就是面向接口开发;
interface ISwim {
swimming: () => void
}
interface IRun {
running: () => void
}
class Person implements ISwim,IRun {
swimming() {
console.log("swimming")
}
running() {
console.log("running")
}
}
function swim(swimmer:ISwim) {
swimmer.swimming()
}
const p = new Person()
swim(p)
1.7:交叉类型
在开发中,我们进行交叉时,通常是对对象类型进行交叉的
interface Colorful {
color: string
}
interface IRun {
running: () => void
}
type NewType = Colorful & IRun
const obj: NewType = {
color: "red",
running:function(){}
}
- interface和type区别
1.interface和type都可以用来定义对象类型
2.如果是定义非对象类型,通常推荐使用type
3.如果是定义对象类型,那么他们是有区别的:
i: pinterface 可以重复的对某个接口来定义属性和方法;
ii: p而type定义的是别名,别名是不能重复的
1.8:字面量赋值
interface IPerson {
name: string
eating: () => void
}
const p: IPerson = {
name: "xiaobai",
age: 18,
eating: function(){}
}
//会报错
interface IPerson {
name: string
eating: () => void
}
const p = {
name: "xiaobai",
age: 18,
eating: function(){}
}
const p: IPerson = obj
这样就不会了
这是因为TypeScript在字面量直接赋值的过程中,为了进行类型推导会进行严格的类型限制。
但是之后如果我们是将一个 变量标识符 赋值给其他的变量时,会进行freshness擦除操作。
2.范型
泛型实现类型参数化
function foo(arg: any): any {
return arg
}
foo("abc")
foo(123)
以下是范型
function foo<Type>(arg: Type): Type {
return arg
}
foo<string>("abc")
foo<number>(123)
当然我们也可以传入多个类型:
function foo<T,E>(a1: T, a2: E){}
平时在开发中我们可能会看到一些常用的名称:
- T : Type:类型
- K、V:key和value,键值对
- E:Element元素
- O:Object对象
interface IFoo<T> {
initialValue: T,
valueList: T[],
handleValue: (value: T) => void
}
const foo: IFoo<number> = {
initialValue: 0,
valueList: [0,1,3],
handleValue: function(value: number) {
console.log(value)
}
}
2.1:泛型类
class Point<T> {
x: T
y: T
constructor(x: T,y: T) {
this.x = x
this.y = y
}
}
const p1 = new Point(10,20)
const p2 = new Point<number>(10,20)
const p3: Point<number> = new Point(10,20)
2.2:泛型约束
有时候我们希望传入的类型有某些共性,但是这些共性可能不是在同一种类型中:
比如string和array都是有length的,或者某些对象也是会有length属性的;
那么只要是拥有length的属性都可以作为我们的参数类型,那么应该如何操作呢?
interface ILength {
length: number
}
function getLength<T extends ILength>(args: T) {
return args.length
}
console.log(getLength("abc"))
console.log(getLength(["abc","cba"]))
console.log(getLength({length:100,name:"xiaobai"}))