【TS基础】个人学习记录5-对象、函数、数组、类中的接口规范

接口概念

我觉得可以把接口看成是个面向对象类型变量的定义规范。

比方定义一个对象的规范,用关键词interface去定义:

interface Person {
    name: string;
    age: number;
    // 函数写法
    // fn?: (number) => number;
    // add: (a: number, b: number) => number;
}

let p: Person = { // 使用了Person的定义规范,就必须遵循,属性多了少了都会报错
    name: 'p',
    age: 25
};

注意:编译成es5后,接口的定义会被去掉!


对象接口定义

可选属性

符号去定义接口内的属性,可以变成一个可选属性:

interface Person {
    name: string;
    age?: number;
}

let p: Person = {  // 这样就不一定要去设置那个可选属性
    name: 'p'
};

任意属性(索引签名)

接口开放个自定义属性:

interface Person {
    name: string;
    age?: number;
    [A: string]: any;  // 自定义属性----key为string类型,val为任意类型
    // 或者[A: string]: string | number;
    readonly [B: number]: string ; // key为number类型,val为字符串类型
}

let p: Person = {
    name: 'p',
    gender: 'male',
    1: '1'
};

注意

  • 自定义key的属性中value值的类型一定要是其他同类型key属性中value值的父集。比如上面的name: stringage?: number中,自定义属性为string的val类型any就是包含了stringnumber。而自定义属性为number的val类型string,因为没有其他key定义数字类型,所以就不受限制。
  • key只能为string或者number类型。

还有一种写法,不在接口中做文章:

interface Person {
	name: string;
    age: number;
}
let obj : {[key: string]: Person } = {
	1 : {name: 'p', gender: 'male'},
	2 : {name: 'p', gender: 'male'},
}

当然,自定义属性也是有缺点的,ts不允许只同时声明不同类型的自定义属性:

interface HA{
    [rank: number]: string; // ts(2413) 数字索引类型 string 类型不能赋值给字符串索引类型 number
    [prop: string]: number;
  }

只读属性

就理解成变量申明的时候就定下来,之后不可再次修改的属性:

interface Person {
    readonly id: number;
    readonly age: number;
    name: string;
}

let tom: Person = {
    id: 1,
    name: 'p',
};

tom.id = 2; // 会报错
tom.age = 18 // 会报错,就算你变量申明的时候没有赋值也不给修改了

函数接口的定义

整体定义

interface Fn {
	(x: number, y: number): number // 定义了入参和返回值类型
}
let fn: Fn
fn = function(x: number, y: number): number {
	return x+y
}

入参定义

interface X{
    name: string;
}
function fn(x: X) {
    return x.name;
}

注意:如果是不完全遵循接口的变量做入参可以比接口定义的属性多,如果是直接在函数形参上直接写的话,就必须严格遵循接口定义。都不推荐这么搞。

interface X{
    name: string;
}
let str = {name: 'xiaoming', age: 12}
function fn(x: X) {
    return x.name;
}
fn(str) // 不会报错
fn({name: 'xiaoming', age: 12}) // 报错

上面的现象(变量做入参可以比接口定义的属性多)是因为TS采用的是鸭子类型,像java的话就比较严格,不能这么搞。

实际开发中还是会以类型别名的方式去规范函数,因为方便。


数组接口的定义

interface Arr {
	[index: number]: number // 意思就是下标为number类型,子项也为number类型
}
let arr: Arr = [1, 2, 3]

数组接口也叫可索引接口,如果把索引改成非数字,就变成对象属性为索引的接口了,一般不会这么写:

interface Obj{
	[index: string]: string
}
let obj: Obj = {name: 'wow'}  // 不推荐这样写

类接口的定义

用关键词implements来指定接口:

interface Alarm {
	name: string;
    alert(): void;
}

interface Light {
    lightOn(): void;
    lightOff(): void;
}

class Car implements Alarm, Light { // 类的声明按照接口定义
	name: string;
	constructor(name: string){
		this.name = name
	}
    alert() {
        console.log('Car alert');
    }
    lightOn() {
        console.log('Car light on');
    }
    lightOff() {
        console.log('Car light off');
    }
}


// 当既有继承又有接口时
class Plane {}
class SmallPlane extends Plane implements Alarm {  // 应该是从左向右看的,SmallPlane 继承Plane ,并且要符合Alarm 接口
	name: string;
	constructor(name: string){
		super()
		this.name = name
	}
	alert() {
		console.log('xxxx')
	}
}

接口与接口的继承

interface A {
    name: string;
	fn: (number) => number
}
interface B extends A{
	name: string // name:number 会报错
}
// 此时B也有了A的内容,并且B的name覆盖了A的,当然他们之间的name不能定义为不同的类型,会报错

接口继承类

class Point {
    x: number;
    y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

具体为什么在TS中接口能够继承类看这个文章:接口继承类。不过应该很少会用到。

泛型接口的定义

看我这篇文章,了解泛型,然后看给接口设置泛型这个标题。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值