TypeScript之接口&函数
一、什么是接口?
在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implements)。
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
二、接口的实现
// 用接口定义对象
interface List {
name: string,
age: number, // 必选属性
job?: string, //可选属性,表示不是必须的参数,
readonly id: number; // readonly 只读属性
[ propName : string ] : any, // 任意类型
}
interface Result {
data: List[]
}
function render(result: Result){
result.data.forEach(value => {
console.log(value.id, value.name)
if(value.age){
console.log(value.age)
}
// value.id ++
})
}
let result = {
data: [
{id: 1, name: 'A', age: 12, sex: 'male'},
{id: 2, name: 'B', age: 10}
]
}
render(result)
上面例子中的就是一个接口的实例,利用接口约束了接收变量的类型,注意,在赋值时:变量的类型必须和接口的形状保持一致。
接口类型有以下几种属性可选
-
必选属性 => ":" 带冒号的属性是必须存在的,不可以多也不能少
-
可选属性 => " ? " 表示有选择的选项,可有可无
-
只读属性 => " readonly " 对象的字段只在创建的时候赋值,注意哦,注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:
-
任意属性 [ propName : 类型 ] : any 表示定义了任意属性取string 类型的值
三、可索引接口:数组、对象的约束(不常用)
1、对数组的约束
interface StringArray {
[index: number]: string;
} // 用任意的number去索引StringArray,最后得到的是一个字符串的数组
let chars: StringArray = ['A', 'B']
interface Names {
// [x: string]: string // 字符串索引签名
[x: string]: any
// y: number
// [z: number]: string // 数字索引签名
[z: number]: number
}
注:数字索引签名的返回值一定是字符串索引签名返回值的子类型,因为js会进行转换,将number转换成string,保证类型的兼容性
2、对对象的约束
interface UserObj{
[index : string] : string // 讨论点:为啥一定是string,而不能是number
}
var arr : UserObj = { name : '张三' };
四、函数的定义
1、函数声明
function add1(x: number, y: string) : string {
return x + y
}
console.log('add1', add1(3, '4'))
形式和JavaScript中的函数声明一样,但不一样的是:
- 指定了参数的类型(因为有类型检查,所以要遵循),随后指定了返回值的类型,这个时候返回值类型可以省略,因为typescript会根据返回语句自动推断出返回值的类型。
- 参数不可多不可少,只能刚刚好,且和顺序有关。
2、函数声明的方式有哪些?
function add1(x: number, y: string) {
return x + y
}
let add2: (x: number, y: number) => number
type add3 = (x: number, y: number) => number
interface add4 {
(x: number, y: number): number
}
3、函数表达式
1)左边的student的类型定义是通过赋值操作进行类型推论而推断出来的,并没有给student指定类型定义。
let student = function(x:string,y:number):string{
return `我是${x},今年${y}岁`;
}
console.log(student("wzy",22)); // 我是wzy,今年22岁
2)如果要给student指定类型的话,应该是这样:
let student:(x:string,y:number)=>string = function(x:string,y:number):string{
return `我是${x},今年${y}岁`;
}
console.log(student("wzy",22)); // 我是wzy,今年22岁
注:1.前后参数名称可以不一致
2.当没有返回值的时候使用void
4、定义一个可选参数
function add5(x : number, y ?: number){
return y ? x + y : x;
}
add5(4)
之前提到过函数的参数是不可多不可少的,但是也可以像接口那样的形式用?表示可选参数
注:可选参数必须位于必需参数后
5、定义默认参数
function add6(x: number, y = 0, z: number, q = 1){
return x + y + z + q
}
add6(2, undefined, 4)
注:必传参数前的默认参数必传,如果没有,用undefined代替
6、定义剩余参数
function add7(x : number, ...rest: number[]){ // 剩余参数,即不知道参数的个数
return x + rest.reduce((pre, cur) => pre + cur)
}
console.log(add7(1,2,3,4,5))
当你想同时操作多个参数或者你并不知道会有多少个参数会传进来时可以采用剩余参数定义
-
在JavaScript中,可以使用arguments来访问所有传入的参数。
-
在typescript里,可以把所有参数收集到一个变量里
注:
(1)剩余参数会被当做个数不限的可选参数,可以一个都没有,也可以有任意个。同样要放在必要参数后面。
(2)是数组类型,名字是省略号后面的字段名,可以在函数体内使用这个数组。
(3)当调用函数时,别传入数组,依次传入就行。
7、函数重载(不需要为相似函数选取不同的函数名称)
function add8(...rest: number[]) : number;
function add8(...rest: string[]) : string;
function add8(...rest: any[]) : any {
let first = rest[0];
if(typeof first === 'string'){
return rest.join('')
}
if(typeof first === 'number'){
return rest.reduce((pre, cur) => pre + cur)
}
}
console.log(add8(1,2,3))
console.log(add8('2','add', 'asd'))
注:TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。