TS 能推导出函数体中的类型,但多数情况下无法推导出参数的类型,只有少数特殊情况下能根据上下文推导参数的类型。返回类型能推导出,不过也可以显式注解。
1 声明和调用函数
一般来说,在方法中的this值为调用该方法时位于点号左侧的对象:
let x = {fun() {console.log(this);}
}
x.fun(); // { fun: [Function: fun] }
let fun = x.fun;
fun(); // undefined
如果在函数中有使用到this,则上面的方法定义是可能会带来风险的(this不能保证为想要的类型)。
我们可以在函数的第一个参数中,声明this的类型,来规避上面的风险。
let x = {fun(this: Date) {console.log(this.getDate());}
}
let date = new Date();
x.fun.bind(date)(); // 27
//x.fun(); // The this context of type { fun(this: Date): void; } is not assignable to method's this of type Date
1.1 函数类型重载
重载函数,即有多个调用签名的函数。
type Reserve = {(from: Date, to: Date, destination: String):String,(from: Date, destination: String):String
}
let reserve: Reserve = (from: Date, to: Date | String,destination?: String) => {return "destination:" + destination;
}
reserve(new Date(), new Date(),"hello");
reserve(new Date(),"ts");
注意,我们在调用函数时,参数类型不是参照这个函数定义时的类型,而是这个函数的签名,例如上面,如果参照函数定义,则函数调用可以为:
图 函数调用失败
如上图所示,上面的调用方式将会报错。
1.1.1 DOM 中的重载
浏览器DOM API有大量重载,例如createElement方法。参数为表示HTML标签的字符串,返回值为对应类型的HTML元素,其函数定义为:
type CreateElement = {(tag: 'a'): HTMLAnchorElement,(tag: 'canvas'): HTMLCanvasElement,(tag: 'table'): HTMLTableElement,(tag: string): HTMLElement
}
2 多态
在类型层面施加约束的占位类型,也称多态类型参数。
type Filter = {<T>(array: T[], f: (item: T) => boolean): T[]
}
let filter: Filter = (array, f) => {let arr = []for (let item of array) {if (f(item)) arr.push(item);}return arr;
}
filter([2,5,7,6],(_) => _ > 5); // [7,6]
<T>在调用签名中声明(位于签名的开始圆括号前面),TS将在调用该类型的函数时为T绑定具体类型。
而如果把T的作用域限定在类型别名中,TS则要求在使用类型别名时显式绑定类型:
type Filter<T> = {(array: T[], f: (item: T) => boolean): T[]
}
let filter: Filter<number> = (array, f) => {let arr = []for (let item of array) {if (f(item)) arr.push(item);}return arr;
}
filter([2,5,7,6],(_) => _ > 5); // [7,6]
2.1 受限的多态
TS 多态可以像Java一样使用extends来约束多态(但不能使用super)。
type TreeNode = {value: string
}
type LeafNode = TreeNode & {isLeaf: true
}
type InnerNode = TreeNode & {children: [TreeNode] | [TreeNode,TreeNode]
}
function mapNode<T extends TreeNode>(node: T,f: (value: string) => string) : T {return {...node,value: f(node.value)}
}
2.2 泛型默认类型
泛型参数可以指定默认类型。
type AString = {value: "a"
}
type BNum = {num: 1
}
type MyString<T extends AString = AString & BNum> = {value: T
}
let myString: MyString = {value: { value: "a", num: 1}
}