1、在函数中声明this
TypeScript 将通过代码流分析推断函数中应该是什么,例如以下内容:this
const cat = { name: '拿破仑', age: 5, content: '', say: function (){ this.content = 'hello world !!!' } }
TypeScript理解函数cat.say有一个对应的this,它是外部对象用户。这对很多情况来说已经足够了,但在很多情况下,您需要更多地控制它所代表的对象。JavaScript规范规定不能有一个名为this的参数,因此TypeScript使用该语法空间来在函数体中声明this的类型。
type User = { name: string, age: number } function getDB () { let filterUsers = function(params: any) :string { return '' } return {filterUsers}; } interface DB { filterUsers(filter: (this: User) => boolean): User[]; } const db = getDB(); const user = db.filterUsers(function (this: User) { return this.name; });
这种模式在回调风格的API中很常见,其中另一个对象通常控制何时调用函数。请注意,您需要使用函数而不是箭头函数来获得此行为:
const admins = db.filterUsers(()=>this.name); // 类型“typeof globalThis”上不存在属性“name”。
2、其他需要知道的类型
在处理函数类型时,您需要识别一些经常出现的其他类型。与所有类型一样,您可以在任何地方使用它们,但这些类型在函数的上下文中尤其相关。
2.1 void
void表示不返回值的函数的返回值。每当函数没有任何返回语句,或者没有从这些返回语句返回任何显式值时,它都是推断类型:
function cat() { let catArr = ['波斯猫', '橘猫', '拿破仑'] for(let i = 0; i< catArr.length; i++){ console.log(catArr[i]); } }
在JavaScript中,不返回任何值的函数将隐式返回未定义的值。然而,在TypeScript中,void和undefined不是一回事。
注意:void与undefined不一样的。
2.2 object
特殊类型对象指的是任何不是基本类型的值(字符串、数字、bigint、布尔值、符号、null或未定义)。这不同于空对象类型{},也不同于全局类型Object。很可能您永远不会使用Object。
注意:object 不是 Object,应经常使用 object!
2.3 unknow
未知类型表示任何值。这类似于任何类型,但更安全,因为做任何未知值的事情都是不合法的:
function cat(params: any) { params.say(); } function catCopy(params: unknown){ params.say(); // “params”的类型为“未知”。 }
这在描述函数类型时很有用,因为您可以描述接受任何值而不在函数体中具有任何值的函数。
相反,您可以描述一个返回未知类型值的函数:
function cat(params: any): unknown { return params.xxx(); } const result = cat('hello world !!!') // 随便编译没有报错,我们还是需要注意result返回的结果。
2.4 never
函数从不返回值:
function getError(msg: string) : never { throw new Error(msg) }
never类型表示从未观察到的值。在返回类型中,这意味着函数抛出异常或终止程序的执行。
当TypeScript确定联合中没有剩余内容时,也不会出现。
function fn(msg: string | number | boolean) { if (typeof msg === 'string'){ // TODO }else if(typeof msg === 'number'){ // TODO }else if(typeof msg === 'boolean'){ // TODO }else{ console.log(); // 这里类型是never } }
2.5 Function
全局类型Function描述了JavaScript中所有函数值上的绑定、调用、应用等属性。它还具有一个特殊的特性,即函数类型的值总是可以被调用;这些调用返回any:
function fn(f: Function) { return f(); }
这是一个非类型化的函数调用,通常最好避免,因为任何返回类型都不安全。
如果您需要接受任意函数,但不打算调用它,则类型()=>void 通常更安全
3、其余参数(rest)和参数
除了使用可选参数或重载来生成可以接受各种固定参数计数的函数外,我们还可以使用rest参数定义接受无限数量参数的函数。
rest参数出现在所有其他参数之后,并使用...语法:
function multiply(n: number, ...m: number[]) { return m.map((x) => n * x); } // 打印值 [10, 20, 30, 40] const a = multiply(10, 1, 2, 3, 4);
在TypeScript中,这些参数上的类型注释隐式地是any[]而不是any,并且给定的任何类型注释的形式都必须是Array<T>或T[],或者元组类型。
相反,我们可以使用spread语法从可迭代对象(例如,数组)中提供可变数量的参数。例如,数组的push方法接受任意数量的参数:
const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; arr1.push(...arr2);
请注意,通常情况下,TypeScript并不认为数组是不可变的。这可能会导致一些令人惊讶的行为:
const args = [8, 5]; const angle = Math.atan2(...args); // 扩张参数必须具有元组类型或传递给 rest 参数。
这种情况的最佳解决方案在一定程度上取决于您的代码,但通常const上下文是最直接的解决方案:
const args = [8, 5] as const; const angle = Math.atan2(...args);
当针对较旧的运行时,使用rest参数可能需要启用downlevelIteration。
4、参数解构
您可以使用参数析构函数来方便地将作为参数提供的对象解包到函数体中的一个或多个局部变量中。在JavaScript中,它看起来是这样的:
function sum({ a, b, c }) { console.log(a + b + c); } sum({ a: 10, b: 3, c: 9 });
对象的类型注释遵循解构语法:
function sum({ a, b, c }: { a: number; b: number; c: number }) { console.log(a + b + c); }
这可能看起来有点冗长,但您也可以在此处使用命名类型:
type ABC = { a: number; b: number; c: number }; function sum({ a, b, c }: ABC) { console.log(a + b + c); }
写一个类似示例,如下图所示:
type cat = { name: string, age: number } function fn(params: cat) { let {name, age} = params; console.log(name, age); } fn({name: '波斯猫', age: 11})
5、函数的可分配性
返回类型void
函数的void返回类型可能会产生一些不寻常但预期的行为。
返回类型为void的上下文类型不会强制函数不返回某些内容。另一种说法是,具有void返回类型(类型voidFunc=()=>void)的上下文函数类型在实现时可以返回任何其他值,但会被忽略。
因此,以下类型()=>void的实现是有效的:
type voidFunc = () => void; const f1: voidFunc = () => { return true; }; const f2: voidFunc = () => true; const f3: voidFunc = function () { return true; };
当其中一个函数的返回值被分配给另一个变量时,它将保留void类型:
const v1 = f1(); const v2 = f2(); const v3 = f3();
即使Array.prototype.push返回一个数字,而Array.prototype.forEach方法需要一个返回类型为void的函数,但存在这种行为是为了使以下代码有效。
const src = [1, 2, 3]; const dst = [0]; src.forEach((el) => dst.push(el));
还有一种特殊情况需要注意,当文字函数定义具有void返回类型时,该函数不得返回任何内容。
function f2(): void { // @ts-expect-error return true; } const f3 = function (): void { // @ts-expect-error return true; };
注意: 在ts5.2 是可以返回的,如下图所示: