四、高级数据类型
1. 接口(interface)
(1) 接口定义变量和函数参数的类型
//定义接口,给对象使用
interface InfoItf{
name:string,
age:number,
height:string
}
let obj:InfoItf = {
name: 'Lucy',
age: 14,
height: '175'
}
//定义接口,给数组使用
interface ArrItf {
[idx:number]:number
}
let arr:ArrItf = [1,3,4]
//定义接口:给函数使用
interface fnItf {
(p:string,a:number):void
}
let fn:fnItf = (p:string,a:number)=>{}
fn('',1)
注意:
1. 很少使用接口类型来定义函数的类型,更多使用内联类型或类型别名配合箭头函数语法来定义函数类型;
(2) 接口继承
多个不同接口之间是可以实现继承的,但是如果继承的接口Person和被继承的接口NameItf有相同的属性,并且类型不兼容,那么就会报错。
interface NameItf{
name:string,
}
interface AgeItf{
age: number
}
//接口继承
interface Person extends NameItf, AgeItf{
height:number
}
let info:Person = {
name: 'Lucy',
age: 16,
height: 163
}
(3) 多个相同接口
多个相同名字的接口,会进行合并,得到一个新的接口;这个接口的特性一般用在扩展第三方库的接口类型。
interface Person {
name: string,
age: number
}
interface Person {
name: string,
height: number
}
let info:Person = {
name: 'Lucy',
age: 20,
height: 175
}
(4) 缺省和只读特性
interface PersonInfo {
name?: string; // 缺省
readonly age: number; // 只读
}
2. 类型别名(type)
接口类型的一个作用是将内联类型抽离出来,从而实现类型可复用。其实,我们也可以使用类型别名接收抽离出来的内联类型实现复用。格式:type
别名名称 = 类型定义。
type Info = {name:string,age:number}
let person:Info = {
name:'Lucy',
age: 14
}
看上面对type的基本使用,这跟interface使用方法不是重复了吗?其实不然,类型别名可以针对接口没法覆盖的场景,例如组合类型、交叉类型等;详情见另一篇笔记:Interface和Type的区别
3.函数类型
(1) 函数常规写法
//函数最初的写法
function fn(a:number,b:number):number{
return a+b
}
//用interface定义接口的写法
interface FnType{
(p:string):number
}
let fn:FnType = (p:string)=>{
return 2
}
//调用函数
fn('')
//用type方式来定义接口
type FnType = {
(p:string):void
}
let fn:FnType = (p:string):void =>{}
fn('')
(2) 函数传参
function fn(a:number,b:number){
return 1
}
fn(1,2); //这个是函数的常规写法没有问题,不会报错
如果只调用函数的时候只传一个参数呢?如:fn(1);
默认传参形式1:
//默认参数,参数名b:number=2,b的默认参数就是2
function fn(a:number,b:number=2){
return 1
}
默认传参形式2:
//默认参数,参数名b加上?号,代表参数可以缺省
function fn(a:number,b?:number){
return 1
}
默认传参形式3:
//剩余参数
function fn(a:number,b:number,...arr:number[]){
console.log(a,b,arr)
}
fn(1,2,3,4,5,6) //很多个参数,用...剩余参数的形式
4.泛型
泛型指的是类型参数化 ,即将原来某种具体的类型进行参数化。设计泛型的目的在于有效约束类型成员之间的关系,比如函数参数和返回值、类或者接口成员和方法之间的关系。
我们用ts定义函数,写法如下,参数传递时内容会越来越多,如果把参数类型内容业抽离出来呢?
function fn(n:number|string):number|string{
return n
}
fn(100);
fn('1234')
比如我们就可以写成下面这样:
function fn<T>(n:T):T{
return n
}
fn<number>(100)
fn<string>('123')
泛型类型
//定义数组类型
let arr:Array<number> = [1,3,4]
let arr1:Array<string> = ['1','2']
//类型别名
type typeFn<P> = (params:P) =>P;
let fnType:typeFn<number> = (n:number) =>{
return n
}
let fn1:typeFn<string> = (p: string):string => {
return p;
}
// 定义接口类型
interface TypeItf<P> {
name: P;
getName: (p: P) => P;
}
let t1: TypeItf<number> = {
name: 123,
getName: (n: number) => {
return n;
},
};
let t2: TypeItf<string> = {
name: "123",
getName: (n: string) => {
return n;
},
};
泛型约束
把泛型入参限定在一个相对更明确的集合内,以便对入参进行约束。
interface TypeItf<P extends string | number> {
name: P;
getName: (p: P) => P;
}
let t1: TypeItf<number> = {
name: 123,
getName: (n: number) => {
return n;
},
};
let t2: TypeItf<string> = {
name: "123",
getName: (n: string) => {
return n;
},
};