TypeScript 中的箭头函数与 JavaScript 中的箭头函数之间的区别
当涉及到 TypeScript 中的箭头函数与 JavaScript 中的箭头函数之间的区别时,有几个关键的差异需要注意:
- 类型注解:TypeScript 允许为箭头函数提供参数和返回类型的类型注解,这使得函数的输入和输出类型可以明确地指定。这对于代码的可读性和类型检查非常有用。例如:
这里的类型是(x: number, y: number) => number
,表示函数接受两个number类型的变量,并返回一个number类型的值
// TypeScript
const add: (x: number, y: number) => number = (x, y) => x + y;
// JavaScript
const add = (x, y) => x + y;
- 上下文类型推断:在 TypeScript 中,当使用箭头函数作为回调函数或赋值给变量时,编译器可以根据上下文中的类型推断函数的参数类型和返回类型。这意味着在某些情况下,您不需要显式指定箭头函数的类型注解。例如:
// TypeScript
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map((num) => num * 2);
// JavaScript
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map((num) => num * 2);
在上述示例中,TypeScript 可以根据 numbers.map
的类型推断出回调函数的参数类型为 number
,并且可以根据 numbers
的元素类型推断出返回类型为 number[]
。
- 箭头函数中的
this
:在 JavaScript 中,箭头函数没有自己的this
值,而是继承自外围作用域的this
值。这意味着箭头函数中的this
与定义函数时的上下文无关,并且无法使用call
、apply
和bind
方法来改变它。相比之下,在常规的 JavaScript 函数中,this
的值根据函数如何被调用来确定。在 TypeScript 中,箭头函数的this
行为与 JavaScript 中保持一致。例如:
// TypeScript
const obj = {
name: "Alice",
sayHello: function () {
setTimeout(() => {
console.log("Hello, " + this.name);
}, 1000);
},
};
obj.sayHello(); // 输出 "Hello, Alice",箭头函数继承了外围作用域的 this 值
// JavaScript
const obj = {
name: "Alice",
sayHello: function () {
setTimeout(function () {
console.log("Hello, " + this.name);
}, 1000);
},
};
obj.sayHello(); // 输出 "Hello, undefined",普通函数中的 this 值受调用方式影响
在上述 TypeScript 示例中,箭头函数内的 this.name
访问了外部函数的 this.name
,而普通函数的 this
指向了全局对象(
在浏览器中通常是 window
),因此输出为 undefined
。
总结来说,TypeScript 的箭头函数在语法上与 JavaScript 的箭头函数非常相似,但通过类型注解和上下文类型推断提供了更强大的类型系统支持,并且继承了 JavaScript 中箭头函数中的 this
行为。这些功能使得箭头函数在 TypeScript 中更加灵活和可靠。
来点例子试一试
这里的类型是( connection: Connection ) => void
表示该函数接受一个 connection参数,然后没有返回值
export const enableBetterErrorHandlingAndLogging: (
connection: Connection
) => void = connection => {
const connectionConsole = useConnectionConsole(connection, { trace: false });
console.log = connectionConsole('log');
console.info = connectionConsole('info');
console.error = connectionConsole('error');
process.on('uncaughtException', handleError);
process.on('unhandledRejection', handleError);
};
这里的类型是( documents: TextDocuments<TextDocument> ) => (params: Params) => Promise<Result[]>
表示该函数接受一个 documents 参数,然后返回一个函数,返回的函数接受一个 params 参数,返回一个 Promise,解析为 Result[] 数组。
export const autoRenameTag: (
documents: TextDocuments<TextDocument>
) => (params: Params) => Promise<Result[]> =
(documents) =>
async ({ textDocument, tags }) => {
await new Promise((r) => setTimeout(r, 20));
const document = documents.get(textDocument.uri);
if (!document) {
return NULL_AUTO_RENAME_TAG_RESULT;
}
if (textDocument.version !== document.version) {
return NULL_AUTO_RENAME_TAG_RESULT;
}
const text = document.getText();
const results: Result[] = tags
.map((tag) => {
const result = doAutoRenameTag(
text,
tag.offset,
tag.word,
tag.oldWord,
document.languageId
);
if (!result) {
return result;
}
(result as any).originalOffset = tag.offset;
(result as any).originalWord = tag.word;
return result as Result;
})
.filter(Boolean) as Result[];
return results;
};
技巧
其实总结下ts函数阅读技巧,就是看第一个:
到=
之间的内容,就是ts类型
再来看下更套娃的
如果函数返回函数,返回函数再返回函数,再返回函数再再返回函数,则箭头函数则需要无限套娃定义ts类型,比如下方代码
这里的类型是( connection: Connection, { trace }: { trace?: boolean } ) => (method: 'log' | 'info' | 'error') => (...args: any[]) => void
该函数的参数:
connection:表示与某个连接相关的对象。
{ trace }:可选的配置对象,包含一个布尔类型的属性 trace,用于指示是否输出跟踪信息。
该函数返回一个函数,返回函数的参数为 method,表示要进行的操作类型,可以是 ‘log’、‘info’ 或 ‘error’。返回函数再次返回一个函数,再次返回函数的接受任意数量的参数,并将这些参数作为数组中的元素进行处理,再次返回函数最后没有返回值。
const useConnectionConsole: (
connection: Connection,
{ trace }: { trace?: boolean }
) => (method: 'log' | 'info' | 'error') => (...args: any[]) => void =
(connection, { trace = false } = {}) =>
method =>
(...args) => {
if (trace) {
const stack = new Error().stack || '';
let file = stack.split('\n')[2];
file = file.slice(file.indexOf('at') + 'at'.length, -1);
const match = file.match(/(.*):(\d+):(\d+)$/);
if (match) {
const [_, path, line, column] = match;
connection.console[method]('at ' + path + ':' + line);
}
}
const stringify: (arg: any) => string = arg => {
if (arg && arg.toString) {
if (arg.toString() === '[object Promise]') {
return JSON.stringify(arg);
}
if (arg.toString() === '[object Object]') {
return JSON.stringify(arg);
}
return arg;
}
return JSON.stringify(arg);
};
connection.console[method](args.map(stringify).join(''));
};