接口
//js写代码方式 你不知道user对象需要传入什么属性 除非你写注释什么的 注释只起个提示错误却不能提示语法错误 const getUserInfo = user => { return `name:${user.name};age:${user.age}` } getUserInfo({}) // //进化一下 函数调用约束对象传参; 缺点是把函数代码写的过长不方便阅读 这个时候就应该用接口了interface const getUserInfo1 = (user: { name: string, age: number, }): string => { return `name:${user.name};age:${user.age}` } getUserInfo1({ name: 'zs', age: 10 }) //下面三种都有错误提示 // getUserInfo1({name:'zs'}) // getUserInfo1({age:10}) // getUserInfo1({name:'zs',age:10,gender:'male'}) // 再进化一下 用interface约束对象 这个接口也可以重复使用 接口和函数定义参数实现分离
普通接口
直接赋值
interface IWarningButton { class: "warning" //接口属性可以是具体的值 text1: '修改' } const warningButton:IWarningButton={class: "warning",text1:'修改'} //但是赋值也是同样的值 不能改为其他值
接口可以嵌套,有更深的子类型
interface IPerson { name: string age: number job: { jobName: string place: string } interests: Array<{ name: string, lever: number }> }
函数类型接口 func:interface
第一种:传入一个一个的参数如add(a,b,c)
直接定义一个函数类型接口
// 如果只是简单的传入一个一个的属性给函数 直接就定义一个函数类型接口 这样就直接知道该传什么参数和不该传什么参数 interface ISearchFunc { (source: string, substring: string): boolean //形参和实参是根据位置定义的 } //按照位置对应的 a=>source b=>substring 名字可以相同 ;也可以不同 并且类型都可以省略 const searchFunc1: ISearchFunc = (a, b) => { //这是最简写方式 推荐使用 return a.includes(b) } //最完整写法 const searchFunc2: ISearchFunc = (source: string, substring: string): boolean => { return source.includes(substring) }
searchFunc1('abc','a)
第二种,传入一个对象 比如getUserInfo(userObj) 这个时候就需要定义对象接口。函数接口看看自己习惯加不加。最好标准化一点:对象接口+函数接口
对象接口+函数接口
//首先定义一个对象接口 interface IUser1 { //定义一个对象接口 readonly id: number name: string age: number } // 然后定义一个函数接口 interface IUserInfoFunc { (user: IUser1): string //看这里 这里就使用了接口自定义类型 ts支持的 } const getUserInfoFunc: IUserInfoFunc = user => { return `name:${user.name};id:${user.id};age:${user.age}` } getUserInfoFunc({ name: 'zs', age: 10, id: 1000 }) //传入一个对象
只定义对象接口
interface IUser { name: string age: number gender?: string readonly id: number //只读属性 也是必须参数 } const getUserInfo1 = (user: IUser): string =>{ return `name:${user.name};id:${user.id};age:${user.age}` }
多层对象函数接口:多个对象接口+一个函数接口
//第一个对象接口 interface Item { readonly id: number name: string age?: number } // 第二个对象接口 interface ItemList { data: Item[] } interface IRenderFunc { (result: ItemList): void } const render: IRenderFunc = result => { result.data.forEach(item => { console.log(item.id, item.name); }) } let result: ItemList = { //最外面对象 data: [ { id: 1, name: 'zs', age: 10 }, //最里面对象 { id: 2, name: 'lisi' } ] } render(result)
字面量类型配合接口
字面量类型用来约束取值只能是某几个预定值中的一个。取其他值就会报错
let num=100|200|300 let str="abc"|"aaa" let aa=100|'100' //然后引出type定义变量 type EventNames = 'click' | 'scroll' | 'mousemove';
//传入一个request对象 type method = 'GET' | 'get' | 'POST' | 'post' //定义对象接口 interface IRequestObj { url: string method: method } interface IRequestFunc { (requestObj: IRequestObj): void } const request: IRequestFunc = requestObj => { console.log(requestObj.url, requestObj.method); } //use request({ url: 'https://www.jianshu.com/p/78b750fb9cd7', method: 'get' }) // 第二种形式:一个一个传入 interface IRequestFunc1 { (url: string, method: method): void //method 是上面type 定义的method } const request1: IRequestFunc1 = (url, method) => { console.log(url, method); } request1('https://www.jianshu.com/p/78b750fb9cd7', 'GET') // 或者这样传 这里的 as const 不是声明变量的关键字,而是 const 类型 ,它会让 const 声明的变量变成真正的字面量类型 const obj = { url: 'https://www.jianshu.com/', method: 'GET' } as const request1(obj.url, obj.method)
总结常见的函数类型接口
interface ISearchFunc { (source: string, substring: string): boolean //形参和实参是根据位置定义的 }
interface IUserInfoFunc { (user: IUser1): string //看这里 这里就使用了接口自定义类型 }
interface ICreateSquareFunc { (config: ISquareConfig): { color: string, area: number } //{ color: string, area: number }返回值也可以定义为一个接口 }
interface ISquareRes { color:string; area:number; } interface ICreateSquareFunc { (config: ISquareConfig): ISquareRes //返回值类型接口 }
类接口 implements
TypeScript也能够用接口来明确的强制一个类去符合某种契约。
//函数类接口 implements interface ISpeakFunc { speak: (words: string) => string // 类的实例方法必须严格按照speak定义去实现 包括参数类型、数量和返回值的类型数量 } interface IEatFunc { eat: () => void } class Person implements ISpeakFunc, IEatFunc { //一个类可以有多个接口实现 speak(a: string) { return 'aa' } // speak(a:number){return 'aa'} Error // speak(a:string,b: string){return 'aa'} Error eat() { } } const p = new Person() p.speak('a')
接口可以继承接口 extends
例子1
//下面这种变量声明不赋值的做法是不允许的 但是ts不会报错
let square: ISquare //变量声明方式1 ts不会编译报错 但是js之后报错 因为编译为js square默认是undefined undefined是点不出color/penWidth属性的
square.color = 'red'
square.penWidth = 10
square.slideLength = 20
let square1 = <ISquare>{} //变量声明方式2 这是强制断言 不是泛型
square1.color = 'blue'
square1.penWidth = 100
square1.slideLength = 200
例子2
interface ISpeakObj { speak: (words: string) => string } // 接口继承 interface ISpeakChinese extends ISpeakObj { speakChinese: (words: string) => string } // 对象必须实现speak方法 const obj: ISpeakChinese = { speak: (word): string => { return word }, //这里其实是没有必要再重新申明类型。不能改变 已经定下来了 speakChinese: (words) => words //这是最好得方式 }
接口多继承
interface IFly { fly: (location: string) => string //这些通通都是属性接口 和name:string性质是一样的 } interface ISwim { swim: (location: string) => string } interface ISport extends ISwim, IFly { //接口多继承 jump: (meter: number) => number } let sport: ISport = { //对象必须得去实现所有接口里面得所有方法 fly: (a) => a,//这里就不用再给a定义数据类型了 就是string类型,而且还不能改a的数据类型 swim(b) { return b }, //也可以用普通函数 但是为了统一和习惯 都用箭头函数 jump: meter => meter }
接口继承type
type Animal ={ name:string age: number } interface Dog extends Animal{} let dog:Dog = {name:'小辉',age:1}
接口继承类
class Person{ name:string age:number } interface IPerson extends Person{} const p1:IPerson={name:'zs',age:18}