ts的函数是js函数的超集,在原有功能基础上增加了,类型系统支持,让函数更安全,更可维护,更易于重构。
1.基本语法:函数生命与类型注解
函数声明:带参数类型和返回值类型
ts
// 函数声明:带参数类型和返回值类型
// function add(...):定义一个叫 add 的函数。
// (a: number, b: number):这个函数接受两个参数,a 和 b,它们都必须是 数字类型(number)。
// : number:表示这个函数的返回值也必须是 数字类型。
// { return a + b; }:函数体,把 a 和 b 相加后返回。
function add(a: number, b: number): number {
return a + b;
}
// 函数表达式
const greet = function(name: string): string {
return "Hello, " + name;
};
// 箭头函数(推荐)
const multiply = (x: number, y: number): number => x * y;
关键点:
参数必须声明类型:a: number
返回值类型可省略(TS 会自动推断),但建议显式写出
箭头函数更简洁,适合回调
greet("小刘")
console.log(greet("小刘"))
//打印结果: Hello,小刘
2.可选参数与默认参数
可选参数:用 ? 表示
ts
// 可选参数:用 ? 表示
//定义一个logMessage的函数,message,userId参数userId?表示用户id可以传也可以不传 。
function logMessage(message: string, userId?: string): void {
//`${...}`:这是 JavaScript 的模板字符串,可以插入变量。
// userId ?? 'Anonymous':这是"空值合并操作符"
// 意思是:如果 userId 是 null 或 undefined(没传),就用 'Anonymous'(匿名)代替。
// 如果传了 userId,就用传的值。
console.log(`[${userId ?? 'Anonymous'}] ${message}`);
}
logMessage("Hello");
logMessage("Hello", "user123");
3.剩余参数
...numbers 是 TypeScript/JavaScript 中一个非常强大又常用的特性,叫做 剩余参数(Rest Parameters)
ts
3.剩余参数(Rest Parameters)
// ...numbers 是 TypeScript/JavaScript 中一个非常强大又常用的特性,叫做 剩余参数(Rest Parameters)。
// ...numbers:意思是"把所有剩下的参数收集到一个叫 numbers 的数组里"
// : number[]:说明这个数组里的每一项都必须是 数字
// 合起来:...numbers: number[] → "接收任意多个数字,把它们放进一个数组"
function sum(...numbers: number[]): number {
return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2); // 3
sum(1, 2, 3, 4); // 10
// ...numbers 必须是最后一个参数
// 为什么 ...numbers 必须是最后一个参数?
// 这是 JavaScript 语言的硬性规则:
// 剩余参数(...)必须放在参数列表的最后,不能有参数跟在它后面。
4.函数重载
同一个函数名,可以根据你传的不同参数,表现出不同的行为,并且有对应的类型提示。
像一个多面手函数,能根据情况自动切换模式。
ts
// 为同一个函数提供多个类型定义,用于不同参数组合。
// 重载签名(没有函数体)
// 重载签名 1:当传两个字符串时,返回 string
function combine(a: string, b: string): string;
// 重载签名 2:当传两个数字时,返回 number
function combine(a: number, b: number): number;
// 实现签名(有函数体,类型最宽)(真正干活的)
function combine(a: any, b: any): any {
return a + b;
}
combine("Hello", "World"); // 返回 string
combine(1, 2); // 返回 number
// combine(1, "2"); // 错误!没有匹配的重载
// 用途:提高类型安全性,让编辑器知道不同调用方式的返回类型
5.类型别名定义函数签名
type是TypeScript 中一个非常优雅的特性:使用 type 定义函数类型,并用它来约束函数的结构。
ts
//定义一个类型别名GreetingFunction,描述这个函数要接收两个参数,name和language可传可不传。
type GreetingFunction = (name: string, language?: string) => string;
//定义一个greetEnglish常量(函数)。
// : GreetingFunction类型注解 表示这个函数必须符合我们上面定义的规则。
// (name) => ...:箭头函数,只传了 name,language 没用到(可选,所以可以不传)
const greetEnglish: GreetingFunction = (name) => `Hello, ${name}`;
const greetChinese: GreetingFunction = (name) => `你好, ${name}`;
greetEnglish("Alice"); // 返回 "Hello, Alice"
greetChinese("小明"); // 返回 "你好, 小明"
// 适合定义回调函数、事件处理器等。
6.泛型函数
让函数支持多种类型,同时保持类型安全。优势:复用性强,类型不丢失
ts
//identity是一个函数,它接收一个参数arg,并原样返回它。(恒等函数)
// <T> 是泛型的语法:T 是一个类型参数(type parameter),它是一个占位符,代表将来会被指定的具体类型。
// arg: T 表示参数 arg 的类型是 T。
// : T 表示函数的返回值类型也是 T。
// 这个函数保证了输入的类型和输出的类型是一致的。
// 这个函数保证了输入的类型和输出的类型是一致的。
function identity<T>(arg: T): T {
return arg;
}
// 这里显式地告诉 TypeScript:T 是 string。
// 所以 arg 必须是 string 类型,返回值也是 string 类型。
// 虽然 "hello" 明显是字符串,但你可以强制指定类型。
identity<string>("hello"); // 显式指定 T 为 string
// 这里没有写 <number>,TypeScript 自动推断(type inference) 出 T 是 number,因为传入的是 42。
// 这是泛型的常见用法:省略类型参数,让编译器自动推断。
identity(42); // 自动推断 T 为 number
// 泛型数组
// 这个函数用于反转一个数组。
// items: T[] 表示传入一个元素类型为 T 的数组。
// 返回值是 T[],即类型为 T 的数组。
// slice() 创建原数组的浅拷贝,reverse() 反转这个拷贝,避免修改原数组。
function reverse<T>(items: T[]): T[] {
return items.slice().reverse();
}
const numbers = [1, 2, 3];
const reversedNumbers = reverse(numbers);
// reversedNumbers: number[],值为 [3, 2, 1]
const words = ["a", "b", "c"];
const reversedWords = reverse(words);
// reversedWords: string[],值为 ["c", "b", "a"]
7.this 类型注解
显示指定this的类型 (尤其在回调中)
ts
// 显式指定 this 的类型(尤其在回调中)
//定义一个handle的类
//它有一个实例属性data,默认值为"hello"
class Handler {
data = "hello";
// 错误:普通函数中 this 可能丢失
// 这里使用了 函数表达式 赋值给实例属性。
// 问题在于:当这个函数被用作事件处理器(比如 button.addEventListener('click', handler.onButtonClick_bad))时,
// this 不再指向 Handler 实例,而是取决于如何被调用。
// 在严格模式下(TypeScript 默认开启),this 会是 undefined,导致 this.data 报错(Cannot read property 'data' of undefined)。
// 原因:JavaScript 中 this 的值由调用方式决定,而不是定义位置。
onButtonClick_bad = function(e) {
// console.log(this.data); //运行时 this 可能是 undefined
}
// 正确:箭头函数自动绑定 this
// 箭头函数 不会创建自己的 this,而是继承外层作用域的 this。
// 在类中,这个外层作用域就是类的构造函数或实例,因此 this 始终指向当前的 Handler 实例。
// 无论这个函数被如何调用(比如作为事件处理器),this.data 都能正确访问。
// 这是现代 TypeScript/JavaScript 中最常用、最推荐的写法。
onButtonClick_good = (e) => {
console.log(this.data); // 正确输出 "hello"
}
// 或者显式注解 this 类型
// 这是一个普通方法,但第一个参数名为 this,类型为 Handler。
// 这是 TypeScript 的特殊语法:显式声明该方法中 this 的类型。
// TypeScript 会检查:只有当这个方法被 Handler 实例调用时才合法。
//例如
const handler = new Handler();
handler.onClick(e); // 正确:this 指向 handler
onClick(this: Handler, e: Event) {
console.log(this.data); // 必须通过 Handler 实例调用
}
}
8.函数类型表达式(function type)
直接定义函数的"类型"
ts
//声明了一个变量 myFunc,指定了它的类型。
//类型是 (a: number, b: string) => boolean;它表示这个函数接受两个参数。
//第一个参数是a和第二个参数是b.
//它返回一个boolean类型(true or false)
let myFunc: (a: number, b: string) => boolean;
//函数赋值
//第一个参数:number x --- 虽然没写类型,但根据上下文,TypeScript 会推断它是 number
//第二个参数:string y --- 同样,TypeScript 推断它是 string
//返回值:boolean return y.length > x --- 比较操作的结果是 true 或 false,即 boolean
myFunc = function(x, y) {
//y 是字符串(string),所以 y.length 是它的字符长度(一个数字)。
// x 是一个数字(number)。
// 这个表达式判断:字符串 y 的长度是否大于数字 x。
// 返回 true 或 false。
return y.length > x;
};
9.构造函数类型(newable)
表示可以被 new
调佣的函数(即类或构造函数)
ts
表示可以被 new 调用的函数(即类或构造函数)
//定义函数createInstance
//参数ctor: { new(): object }
// { new(): object }是一个对象类型字面量,表示"具有构造函数签名的对象"
//new() 表示:这个对象可以被 new 调用(即它是一个类或构造函数)。
//(): object 表示:调用 new 时不需要参数(空括号),并返回一个 object 类型的实例。
//所以,ctor 的类型是一个"无参构造函数,返回一个对象"。
function createInstance(ctor: { new(): object }): object {
//函数体:return new ctor();
// 使用 new 调用传入的构造函数 ctor,创建一个新实例并返回。
// 因为类型系统知道 ctor 是可构造的,所以 new ctor() 是合法的。
返回类型:: object
表示函数返回一个对象(任何对象)。
在实际使用中,返回的其实是 ctor 所代表类的实例。
return new ctor();
}
//定义了一个简单的类 MyClass。
// 它没有构造函数,因此默认有一个无参构造函数。
// 它的实例是一个空对象(但属于 MyClass 类型)。
class MyClass {}
// 把 MyClass 这个类本身(而不是实例)作为参数传给 createInstance。
// MyClass 是一个构造函数,可以被 new 调用,且无参数,符合 { new(): object } 的类型。
// 函数内部执行 new MyClass(),创建一个 MyClass 的实例并返回。
// 调用成功,返回一个 MyClass 的实例。
//虽然 createInstance 的返回类型是 object,你可能需要类型断言才能访问 name 属性(见下文改进)。
createInstance(MyClass);