TypeScript基础-接口

南山隐士 2022年06月25日 28 0

接口

在typescript中, 它会对值进行类型检查, 这是它的核心之一, 而接口的存在就在于, 就是为这些 ==类型命名== 和为 ==你的代码或第三方代码定义契约==

接口初探

function printLabel(labelledObj: { label: string }) {
  console.log(labelledObj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

让我们来看看这个例子, 这里我们定义了一个函数, 它需要接受一个对象作为参数, 而这个对象中,我们需要定义一个名为label的属性

我们可以看到,我们定义一个类型检查似乎比较麻烦, 我们可以考虑, 将这个类型的检查放到别的地方, 这个时候, 我们就需要使用接口来定义了

// 定义一个接口
interface LabeledValue {
  label: string
}

function printLabel(labelledObj: LabeledValue) {
  console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

值得一提的是, ==类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以==

可选属性

在以前javascript函数接受的参数我们只能设置一个默认值, 不能让这个参数是否是可选的, 而typescript可以做到这一点

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

function peopleInfo(info: SquareConfig ): SquareConfig {
  return info
}
let YaoJin = {name: 'YaoJin'}
console.log(peopleInfo(YaoJin))

上面的例子中, 我们就可以来考虑是否传递name或者 age参数了

并且当我们读取不应该存在的属性是, 它会提示

只读属性

只读属性, 定义 readonly 就不能进行修改

interface SquareConfig {
  readonly  name?: string;
  age?: number;
}
function peopleInfo(info: SquareConfig ): SquareConfig {
  info.name = 'EvanYou' // error: Cannot assign to 'name' because it is a read-only property
  return info
}

将上面的例子修改就会报错

TypeScript还具有ReadonlyArray 类型 ,通过这个类型创建的数组, 是没法修改的

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!

不过,我们可以通过类型断言来重写,让它是一个新的类型
a = ro as number[];

额外的属性检查

额外的类型检查是指, typescript会检查你定义接口中, 多传入的参数, 或者说不该存在的参数

// 可选参数
interface SquareConfig {
  readonly  name?: string;
  age?: number;
}
console.log(peopleInfo({name: 'YaoJin', money: 1212})) //error “money”不在类型“SquareConfig”中

当我们传递一个接口中不存在的属性时候, 就会报错, 要解决这个问题, 我们可以使用以下几种办法:

类型断言
通过类型断言,告诉typescript我很清楚知道自己做什么, 这个就是SquareConfig 的接口 需要检查的类型数据, 它是没有问题的

字符串索引签名

interface SquareConfig {
  readonly  name?: string;
  age?: number;
  [propName: string]: any; // 额外的类型检查(解决办法2) 字符串索引签名
}

改变接口的定义,添加一个字符串索引签名, 告诉typescript, 这个接口, 可以接受除name 和 age 额外的属性, 并且这个属性可以任意类型, 我将会在后续讲解 字符串索引签名

复制到一个变量中
还有一种简单粗暴的方法是, 将你想传递的数据,赋值到一个变量中,那么此时, 就会绕开检查, 从而达到想要的结果, 但不推荐这样使用

let YaoJin = {name: 'YaoJin', money: 1212} // 复制到一个变量中,避开检查(解决办法3)

不管趋于什么目的, 我们使用typescript都是为了更好的进行类型判断, 使用这几种办法来避开检查, 可能在比较复杂的情况下,我们才会考虑使用

函数类型

接口不带可以作为对象的类型检查, 它可以定义函数的类型检查, 意思就是我们可以将函数需要进行的类型检查单独写到一个接口中

interface searchPeople {
  (name:string, age: number): void
}

上述代码中, 就是定义了一个函数的类型检查接口

在函数类型中, 函数的参数可以不与你接口定义的名字相匹配

interface searchPeople {
  (name:string, age: number): any
}

let people: searchPeople
people = function (n, a) { // 函数的参数名称不一定要跟接口定义的名称一致, 但类型必须一致
  return {n ,a}
}
console.log(people('YaoJin',  18))

像这样, 我们定义n 和 a 的参数, 不需要像接口中一样,但是类型必须是一致

可索引的类型

通过可索引类型, 我们可以描述对象的索引类型以及应该该索引的值是属于什么类型的数据

interface stringArray {
  [index: number]: string;
  length: number;
}
let strArr:stringArray = ['YaoJin']

上面的例子中,我们描述了数组, 这个对象, 通过索引index 获取的值需要是string类型, 并且定义的值中需要含有length这个属性/索引, 这个时候数组就符合这个情况, 像上面的例子中,我们就可以通过strArr[0]来获取值, 但对象就不行, 因为它符合length这个规则

interface stringObj {
  [index: string]: string,
  name: string
}
let strObj:stringObj ={ name:'YaoJin' }
console.log(strObj['name'])

对象我们可以通过定义类似于上面name这个属性的索引,

说白了,我个人的理解是, 索引类型, 就是告诉ts,我这个对象, 应该需要定义什么索引, 这个索引应该属于什么类型, 并且对应索引的值是属性什么类型, 如果不符合我定义的规则, 那么麻烦你告知我是错误的

类类型

类类型, 可以让接口去定义某些类的检查, 检查当前这个类是否定义了某个公共的方法

interface ClockInterface {
  currentTime: Date;
}

class Clock implements ClockInterface {
  currentTime: Date;
  constructor(h: number, m: number) { 
    this.currentTime = new Date(h, m)
  }
}

上述代码中, clock这个类, 必须含有currentTime 这个公共属性, 并且值的类型需要是一个Date对象

继承接口

和类一样,接口也可以相互继承, 这样, 一个接口, 可以检查多中情况的类型判断

// 继承接口
interface stringFace {
  name: string
}
interface numberFace {
  age: number
}

interface concatFace extends stringFace, numberFace {
  money: number
}

let YaoJinS = <concatFace>{}
YaoJinS.name = 'YaoJin'
YaoJinS.age = 18
YaoJinS.money = 999999999999

混合类型

混合类型可以让我们定义多个类型的检查, 例如定义函数类型和对象类型的检查


interface MixinFace {
  (say: string): string
  age: number;
}

function mixin (): MixinFace {
  let obj = <MixinFace>function (say:string) { return say }
  obj.age = 12
  return obj
}
let a = mixin()
a.age = 18
console.log(a('啊哈啊啊哈'), a.age)

上面的例子中,通过混合类型, 定义了一个对象中, 必须包含一个函数以及一个age属性, 我们通过类型断言, 将其赋值到obj中,此时, obj 这个对象, 就拥有函数以及age的一个对象了

存疑

类类型还不熟悉, 接口继承类还没编写

Last Updated: 2022/06/25 19:14:28
TypeScript基础 -类 TypeScript基础-泛型