【前端】你好,我叫TypeScript 02──变量与接口

TS变量与接口

变量声明

其实TS中的变量声明和JS中是一样的,所以你会JS就会TS,无外乎var、let和const,记住以下的表格内容就能解决绝大多数场景问题。

varletconst
存在变量提升不存在变量提升不存在变量提升
不需要初始化不需要初始化需要初始化赋值
函数作用域块级作用域块级作用域
可以重复声明不可重复声明不可重复声明
全局作用域下,变量会成为window的属性全局作用域下,变量不会成为window的属性全局作用域下,变量不会成为window的属性

接口

在面向对象语言中,接口是个比较核心的概念,其作用就是对类型命名和代码定义契约,其实就是对行为的抽象,对对象的形状进行描述。在TS中就是对值所具有的结构进行类型检查。

// 原始方法
function printLabel(labelObj: {label:string}){
  console.log(labelObj.label);
}
let myObj = {name:"wenbo",label:"size 110"};
printLabel(myObj);

// 接口方法
interface LabelValue {
  label: string;
}

function printLabel2(labelValue:LabelValue){
  console.log(labelValue.label);
  
}
printLabel2(myObj);

上述代码表明,printLabel中传入对象labelObj有string类型的label属性。而传入的对象参数实际会包含很多属性,但是编译器智慧检查那些必须的属性是否存在、类型是否匹配。printLabel2接口其实就是对printLabel中传入对象类型的抽象,定义它的参数行为,类型检查器不会关注属性的顺序。

接口对象的声明方式

接口对象的声明方式很简单,就是在接口名前加上interface即可。

interface myObj {
  name:string;
  label:string;
}

接口对象的基本属性

接口对象的属性无外乎默认属性、可选属性和只读属性等。

  • 默认属性:表示该属性必须存在,可读可改

  • 可选属性:表示该属性可有可无、可读可改,只需要在属性名后加上?符号即可,如:name?:string;。可以对可能存在的属性进行预定义,捕获引用了不存在属性时的错误。

  • 只读属性:表示该属性只能读取、不可修改,只需要在对象创建时对指定属性名前加上readonly即可,可以确保创建后不被修改。

interface LabelValue{
  readonly id: number;//只读属性,表示该属性只能读取、不可修改
  name?: string;//可选属性,表示该属性可有可无
  label: string;//默认属性,表示该属性必须存在
}
function printLabel(labelValue:LabelValue){
  console.log(labelValue);
}

let myObj: LabelValue = {name:"yichuan",id:100,label:"size 110"};
printLabel(myObj);//{ name: 'yichuan', id: 100, label: 'size 110' }

myObj.id = 200;// 报错: Cannot assign to 'id' because it is a constant or a read-only property.

let myObj2: LabelValue ={id:100};
// Type '{ id: number}' is not assignable to type 'LabelValue'.
// Property 'label' is missing in type '{ id: number}'.
// 报错: 缺少 label 属性

接口对象的函数类型

接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。

使用接口表示函数类型,需要给接口定义一个调用签名,是一个只有参数列表和返回值类型的函数,其中参数列表的每个参数都得有属性名和类型。

interface myFun{
  (name:string, age:number): void;//()中的是函数类型,void是否有返回值
}

let iFun: myFun;

iFun = function (name:string,age:number){
  console.log(`my name is ${name}, my age is ${age}`)
}

iFun("yichuan",18);//my name is yichuan, my age is 18

我们可以看到:首先创建了一个函数类型的接口myFun,再创建了一个函数类型的变量iFun,并将同类型的函数赋值给这个变量。

对于函数类型检查而言,函数的参数名不需要与接口定义的名字匹配。类型检查器会对函数参数进行逐个检查,判断对应位置的参数类型是否匹配。当然,如果你在函数中没有指定参数类型,那么TS类型系统会根据接口进行推断,并执行检查是否匹配。

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

let iFun: myFun;

iFun = function (name,age){
  console.log(`my name is ${name}, my age is ${age}`)
}

iFun("yichuan",18);my name is yichuan, my age is 18

接口对象的可索引类型

与使用接口描述函数类型差不多,只不过可索引类型时通过描述对象索引类型和索引返回值类型的索引签名

//定义一个学生列表接口
interface StudentList{
  id: number;
  name: string;
}

// 定义一个班级接口
interface ClassList{
  classname: string;
  students: StudentList[];
  [index: string]: any;//可以用任意的string类型去索引声明的对象, 值是any类型
}

function printLabel(data:ClassList){
  return data;
}

printLabel({
  classname:"class 1",
  numbers:30,
  students:[{
    id:2001,
    name:"yichuan"
  }]
})

可索引接口的类型只可以使用stringnumber进行定义索引签名。可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。当使用 number来索引时,JavaScript会将它转换成string然后再去索引对象。

  • 字符串定义索引签名
  • 数字定义索引签名
  • 混合类型定义索引签名
class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}

// 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
}

字符串索引签名能够很好的描述dictionary模式,并且它们也会确保所有属性与其返回值类型相匹配。因为字符串索引声明了obj.propertyobj["property"]两种形式都可以。

为防止给索引赋值,可以将其索引签名定义为只读类型。

interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!

类接口

TS中可以对类设置强制执行的类型约定,即类接口。

interface FatherInterface{
  firstName: string;
}

class Son implements FatherInterface{
  firstName!: String;
  constructor(lastName:string,age:number){};
}

注意:

  • 接口只描述类的公共部分,而不是公共和私有两部分。它不会帮你检查类是否具有某些私有成员。
  • 类实现接口时,必须实现接口所有的属性
  • 接口无法约束类的构造函数,类型检查器只会对实例部分进行检查

我们知道类具有两种类型:静态部分的类型和实例的类型。当你用构造器签名去定义一个接口并试图定义一个类去实现这个接口时会得到一个错误:只对其实例部分进行类型检查,而constructor存在于类的静态部分,所以不在检查的范围内。

interface FatherInterface{
  new (firstName:string);
}

class Son implements FatherInterface{
  constructor(firstName:string,lastName:string,age:number){};
}

继承接口

和类一样,接口也可以相互继承。可以将一个接口成员复制到另一个接口,灵活地分割接口到可复用模块中。

interface DogInterface{
  type:string;
}

interface Erha extends DogInterface{
  name:string;
  age:number;
}

let erha = <Erha>{};
erha.type = "dog";
erha.name = "bobo";
erha.age = 2;

同样的,接口也可以实现多继承。

class Son implements FatherInterface{
  constructor(firstName:string,lastName:string,age:number){};
}

interface AnimalInterface{
  foal:string;
}

interface DogInterface{
  type:string;
}

interface Erha extends DogInterface, AnimalInterface{
  name:string;
  age:number;
}

let erha = <Erha>{};
erha.type = "dog";
erha.name = "bobo";
erha.age = 2;
erha.foal = "分娩";

小结

interface接口的定义其实很简单,和定义对象一样的形式。接口对象的基本属性包括:默认属性、可选属性以及只读属性,其可索引类型的定义只有stringnumber两种形式,类接口进行继承的形式和类的继承大同小异。

参考文章

写在最后

我是前端小菜鸡,感谢大家的阅读,我将继续和大家分享更多优秀的文章,此文参考了大量书籍和文章,如果有错误和纰漏,希望能给予指正。

感谢大家的阅读,我将继续和大家分享更多优秀的文章,期待大家的关注公众号【前端万有引力】。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值