目录
1、函数类型表达式
// (a: string) => void 意味着 "有一个参数为string的函数,没有返回值"。
function greeter(fn: (a: string) => void) {
fn("Hello, World");
}
function printToConsole(s: string) {
console.log(s);
}
greeter(printToConsole);
// 使用类型别名定义函数
let fun = (a:String) => void;
function greeter(fn: fun){
// ...
}
2、调用签名
在js中函数除了可以用来调用,函数还可以拥有属性。只是在函数类型表达式的语法不允许声明属性。 如果我们想用属性来描述可调用的东西,我们可以在一个对象类型中写一个调用签名。<与函数类型表达式相比,语法略有不同:在参数列表和返回类型之间使用 : 而不是 =>>
type newDataType = {
x: String,
(a: String): Boolean //与函数类型表达式相比,语法略有不同:在参数列表和返回类型之间使用 : 而不是 =>
}
function handleFunction(fn: newDataType){
console.log(fn.x + "return " + fn("hhh"))
}
function fn(str){
return false
}
fn.x = "llllll"
handleFunction(fn)
3、构造签名
在js中函数可以通过new关键词来调用,这在js和ts中称之为构造函数;因为通过new出来的一般都是一个新对象。即可以通过在调用签名的前面添加new关键字来写一个构造签名
class dataType{
s: Number,
constructor(s: Number){
this.s = s;
}
}
type newDataType = {
new (s:Number): dataType
}
function handleType(dType: newDataType){
return new dType(222);
}
console.log(handleType(dataType).s) // 打印出 222
4、泛型函数
在写一个函数时,输入的类型与输出的类型有关,或者两个输入的类型以某种方式相关,这是常见的。 在TypeScript中,当我们想描述两个值之间的对应关系时,会使用泛型。
// 通过给这个函数添加一个类型参数 Type ,并在两个地方使用它,即已经在函数的输入(数组)和输出(返回值)之间建立了一个联系。现在调用它时,一个更具体的类型就出来了
function firstArr<Type>(arr: Type<>){
return arr[0];
}
// 调用函数
// s 的类型这时候就为Number
const s = firstArr([1,2,3,4])
// s1 的类型这时候就为String
const s1 = firstArr(['a','b','c','d'])
// s2 的类型这时候就为undefined
const s2 = firstArr([])
函数泛型的限制条件
// Type 约束为 { length: number } ,所以我们被允许访问 a 和 b 参数的 .length 属性。
// 如果没有类型约束,我们就不能访问一些属性(会报错),因为这些值可能是一些没有长度属性的其他类型。
function longest<Type extends { length: number }>(a: Type, b: Type) {
if (a.length >= b.length) {
return a;
} else {
return b;
}
}
// longerArray 的类型是 'number[]'
const longerArray = longest([1, 2], [1, 2, 3]);
// longerString 是 'alice'|'bob' 的类型。
const longerString = longest("alice", "bob");
// 错误! 数字没有'长度'属性
const notOK = longest(10, 100);
// longerArray 和 longerString 的类型是根据参数推断出来的。
// 泛型就是把两个或多个具有相同类型的值联系起来。
约束条件中常见的错误使用
function handelData<Type extends {length: Number}>(data: Type,flag: Number): Type{
if(data.length > flag){
return data
} else{
return {length: flag} // 错误,因为Type的类型不一定是个对象,即Type不一定要与其 限制值一致
}
}
// 'arr' 获得值: { length: 6 }
const arr = handelData([1, 2, 3], 6);
// 错误,因为数组有一个'切片'方法,但对象没有
console.log(arr.slice(0));
5、指定类型参数
// 指定函数返回的类型为Type[],但是在某些时候调用这个函数会出现错误
function concatArray<Type>(a: Type[],b: Type[]): Type[]{
return a.concat(b)
}
concatArray([1,2,3,4,5],["hello"]) // 报错,正常返回的类型推断的应该是 Number[],现在返回的是一个混合数组,所以函数应该这样更改
concatArray<Number | String>([1,2,3,4,5],["hello"]) // 手动指定类型
6、优秀函数编写的准则
// 1、使用类型参数本身,而不是对其进行约束
function firstElement1<Type>(arr: Type[]) {
return arr[0];
}
function firstElement2<Type extends any[]>(arr: Type) {
return arr[0];
}
// a: number (推荐)
const a = firstElement1([1, 2, 3]);
// b: any (不推荐)
const b = firstElement2([1, 2, 3]);
// 2、总是尽可能少地使用类型参数
function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
return arr.filter(func);
}
// Func extends 就没有要的必要
function filter2<Type, Func extends (arg: Type) => boolean>(
arr: Type[],
func: Func
): Type[] {
return arr.filter(func);
}
// 3、如果一个类型的参数只出现在一个地方,请重新考虑你是否真的需要它
7、函数参数的应用
可选参数:在TypeScript的函数中,传递参数时,在参数的后面加上 ? 就表示该参数是可选参数。注意:虽然可选参数会被指定为某种类型,但该参数实际上将具有 某种类型 | undefined 类型,因为在 JavaScript中未指定的参数会得到 undefined 的值。
当为回调函数写参数是,一定要避免使用可选参数,除非你不打算使用这个参数。
8、函数的重载
在TypeScript中,我们可以通过编写重载签名来指定一个可以以不同方式调用的函数。要做到这一点, 要写一些数量的函数签名(通常是两个或更多)+ 函数的主体:
function makeDate(timestamp: number): Date; // 传递时间戳的重载函数签名
function makeDate(m: number, d: number, y: number): Date;// 传递三个参数(月、日、年)的重载函数签名
// 函数主体
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(12345678); // 传递时间戳
const d2 = makeDate(5, 5, 5); // 传递三个参数
const d3 = makeDate(1, 3); // 错误,因为没有对应的重载函数签名与之对应
9、其他类型
void 表示没有返回值的函数的返回值。当一个函数没有任何返回语句,或者没有从这些返回语句中返回任何明确的值时,它都是推断出来的类型。
unknown 类型代表任何值。这与 any 类型类似,但更安全,因为对未知 unknown 值做任何事情都是不合法的。 这在描述函数类型时很有用,因为你可以描述接受任何值的函数,而不需要在函数体中有 any 值。 反之,你可以描述一个返回未知类型的值的函数。
never 类型表示永远不会被观察到的值。在一个返回类型中,这意味着函数抛出一个异常或终止程序的执行。 never 也出现在TypeScript确定一个 union 中没有任何东西的时候。
10、参数扩展运算符 与 参数解构
function multiply(n: number, ...m: number[]) {
return m.map((x) => n * x);
}
// 'a' 获得的值 [10, 20, 30, 40]
const a = multiply(10, 1, 2, 3, 4);
// 展开数组
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr1.push(...arr2);
// ==============================参数解构==============================
// 函数参数简写版
function sum({ a, b, c }) {
console.log(a + b + c);
}
// 详细版
function sum({ a, b, c }: ABC) {
console.log(a + b + c);
}
sum({ a: 10, b: 3, c: 9 })