从零开始学习typescript系列7: typescript接口interface相关使用详解含demo

[[toc]]

demo:描述普通对象:类型检查

使用interface检查属性类型

interface Person { name: string} // interface定义
function greeter(p: Person){return p.name} //  interface使用

// 1. 隐式类型检查: 检查属性是否存在和匹配,不检查多余属性,不检查顺序
let user1 = {age:20, name: 'san'}; // ✅
console.log("user1: ", greeter(user1));  // user1:  san

// 2. 显式类型检查: 检查属性是否存在和匹配,不能有多余属性,不检查顺序
let user2: Person = {name: 'san'}; // ✅
console.log("user2: ", greeter(user2));  // user2:  san
// let user3:Person = {age:20,name: 'san'};  // ❌ error 'age' does not exist in type 'Person'

// 3. 类型推断 相当于隐式类型检查 
let user4 = {age:20,name: 'san'} as Person; // ✅ 
console.log("user4: ", greeter(user4));  // user4:  san

属性检查分类

  • 隐式类型检查
  • 显式类型检查

类型检查点

  • 属性是否存在?
  • 属性类型是否正确?
  • 属性顺序是否可以随意?
  • 属性是否可以多余?

demo:描述普通对象:可选属性

可选属性

  • 属性名称后接问号
interface SquareConfig { color?: string, width?: number }
let sc1: SquareConfig = {} // ✅ 
let sc2: SquareConfig = {color: 'red'} // ✅ 
let sc3: SquareConfig = {width: 1} // ✅ 
let sc4: SquareConfig = {color: 'red', width: 1}// ✅ 
let sc5 = {color: 'red', opactiy: 1} as SquareConfig // ✅ 
let sc6: SquareConfig =  {colr: 'red', width: 0.5} // ❌  'colr' does not exist in type 'SquareConfig'

demo:描述普通对象:只读属性

只读属性

  • 通过readonly, ReadonlyArray定义
  • 初始化之后,只能读不能写
// 1. 只读属性 readonly
interface Point { readonly x: number; readonly y: number }
let p1: Point = {x: 1, y:2}
console.log(p1.x, p1.y); //✅ 1 2
p1.x = 3; // ❌ Cannot assign to 'x' because it is a read-only property.

// 2. 只读数组 ReadonlyArray
let intArr2: ReadonlyArray<number> = [4,5,6];
console.log(intArr2); // ✅ [ 4, 5, 6 ]
intArr2[0] = 400; //  ❌ Index signature in type 'readonly number[]' only permits reading.

demo:描述函数:什么是函数接口?

  • 描述函数类型,使用接口来描述函数
  • 语法: 对象中仅包含一个函数,没有别的属性
  • 用途: 可以定义多个此结构的函数
// 定义函数接口: 通过接口定义函数类型(参数+返回值)
interface searchFun {(source: string, subString: string) : boolean}
// 使用函数接口定义fun1
let fun1: searchFun = function(src: string, sub:string): boolean{
    return src.search(sub) > -1;
}
// 使用函数接口定义fun2
let fun2: searchFun = function(src: string, sub:string): boolean{
    return src.indexOf(sub) > -1;
}
console.log(fun1('abc123abc', '123'),fun1('abc123abc', '1234')); // true false
console.log(fun2('abc123abc', '123'),fun2('abc123abc', '1234')); // true false

demo:描述函数:对象接口和函数接口区别?

区别(先看例子)

  • 语法: 对象接口里所有函数都有函数名; 函数接口里有个没有函数名的函数定义
  • 作用: 对象接口描述的是对象(里面包含的属性和方法挂在对象上); 函数接口描述的是函数(里面包含的属性和方法挂在函数上)
// 1. 对象接口  
// Schedule描述的是对象❗
interface Schedule {
    start(): void; // 有方法名 作为对象的一个属性
    time: string; // 属性
    end(): void; //  作为对象的一个属性
}
// 使用对象接口
const s1:Schedule = {
    start: function(){console.log('start')},
    time: '20240101',
    end: function(){console.log('end')},
}
// 运行  (打印时间、开始调度、结束调度)
console.log('对象接口')
console.log(s1.time); // 20240101 
s1.start(); // start
s1.end(); // end

// 2. 函数接口 
// Schedule描述的是函数❗
interface Schedule {
    (): void; // 没有方法名 不是对象的一个属性
    start(): void; // 有方法名 作为对象的一个属性
    time: string; // 属性
    end(): void; //  作为对象的一个属性
}
// 使用函数接口 
const genSchedule = function(time:string):Schedule{
    let main = <Schedule>function(){}
    main.time = time;
    main.start = function(){console.log('start')};
    main.end = function(){console.log('end')};
    return main;
}
// 运行  (打印时间、开始调度、结束调度)
console.log('函数接口')
const s1 = genSchedule('20240101'); // 生成s1函数
console.log(s1.time); // 20240101 
s1.start(); // start
s1.end(); // end

demo:描述函数:混合类型接口

接口内包含(先看例子)

  • 函数: 类似函数接口
  • 属性: 挂在函数对象上
  • 方法: 挂在函数对象上
// 定义混合接口
interface Lib {
    (): void; // 没有方法名 不是对象的一个属性,Lib接口描述的是函数❗
    version: string; // 属性
    doSomething(): void; // 方法
}
// 使用混合接口
function genLib (version: string): Lib {
    const lib = <Lib> function() {} // 相当于 let lib = (() => { }) as Lib;
    lib.version = version || "1.0";
    lib.doSomething = () => {console.log("do something")};
    return lib;
}
// 运行
let lib = genLib('2.0') // 返回函数 lib 
console.log(lib.version) // lib属性version  => 2.0
lib.doSomething(); // lib方法doSomething => do something
// 需求: 定义一个函数,实现变量累加

// 方法1 js 全局变量 
// 缺点: count 会污染全局空间
let count = 0;
function demo() {
    console.log(++count);
}
demo(); // 1
demo(); // 2
demo(); // 3

// 方式二(使用闭包) 
// 缺点: 闭包容易使用不当导致内存泄露
let demo = (() => {
    let count = 0;
    return () => {
        console.log(++count);
    }
})();
demo(); // 1
demo(); // 2
demo(); // 3

// 方式三(利用 JS 中函数的本质)
// 思路: JS 中函数本质就是对象,可以直接给该对象添加 count 属性进行累加
function demo() {
    console.log(++demo.count);
}
demo.count=0
demo(); // 1
demo(); // 2
demo(); // 3

// 方式三 TS 版本
interface Counter {
    ():void; // 函数结构, 无参数,无返回值 
    count: number; // 函数带有count属性 
}
// 自执行函数: 匿名函数,参数为空,此处 Counter 作为函数返回值类型
const demo = (function(): Counter{
    // fun 作为函数时符合接口中函数接口的限定 ():void
    // fun 作为对象时符合接口中对象属性的限定 count:number
    // 此处 Counter 是类型断言语法,相当于 as Counter
    const fun = <Counter> function() {console.log(++fun.count)}
    // const fun = function() {console.log(++fun.count)} as Counter;
    fun.count = 0;
    return fun;
})()
demo(); // 1
demo(); // 2
demo(); // 3

demo:描述索引:索引签名 Index Signatures

索引签名是什么?

  • 就是指索引下标: objec.key或者array.index
  • 支持两种索引签名: string,number
  • 注意: 索引签名number和string类型同时存在时,2个的返回值类型需要相同。这是因为当使用 number来索引时,将它转换成string然后再去索引对象。 比如100作为索引等同于"100"作为索引,因此两者返回值类型需要保持一致。
// 1. 索引签名为number
interface Grades {[x: number]: number};
let myGrade: Grades = [90,95,100]; // ✅
let grade0: number = myGrade[0];  // ✅
console.log(`grade0=${grade0}`); // grade0=90

// 2. 索引签名为string 
interface NameGrades {[y: string]: number};
let myNameGrades: NameGrades = {'lily': 80, 'Jonny': 100};  // ✅
let lucyGrades: number = myNameGrades['Jonny'];
console.log(`lucyGrades=${lucyGrades}`); // lucyGrades=100

// 3. 索引签名为number+string 
interface Okay { [x: number]: string; [x: string]: string;}
let myOkay: Okay = {'name': 'micky', 10: 'haha'};
let okRet1: string = myOkay['name']; // ✅ micky
let okRet2: string = myOkay[10]; //  ✅ haha

// 4. 索引签名包含index+length 
// ok length属于字符串索引
interface nameDictionary { [index: number]: number,  length: number}
let myNameDictionary: nameDictionary = [1,2,3]; //  ✅ 

// 5. 索引签名可以设置为只读 
interface ReadonlyStringArray {readonly [index: number]: string;}
let myReadonlyStringArray: ReadonlyStringArray = ['Alice', 'Bob'];
console.log(myReadonlyStringArray[0]); // ✅ 只能读 Alice
// myReadonlyStringArray[0]='Angel' // ❌ 不能写

// 注意:如果2个的返回值类型不同时,编译报错
// ❌ Numeric index type 'number' is not assignable to string index type 'string'.
interface NotOkay { [x: number]: number; [x: string]: string;}

总结

接口是什么?

  1. 用户自定义的类型,定义基本类型中不存在类型
  2. 个人理解:相当于c++的struct, js中的object

接口作用

  • 描述普通对象: 约定对象的kv类型
  • 描述函数: 约定函数输入和输出类型
  • 描述索引: 约定object/array的索引类型
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值