TypeScript 中的函数式编程:高级水平

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

TypeScript中的函数式编程:进阶篇

\n\n

函数式编程(FP)是一种将计算视为数学函数求值,并避免改变状态和可变数据的编程范式。TypeScript 作为 JavaScript 的超集,提供了强大的类型系统,使得我们能够在更高的安全性和表现力层面实现许多 FP 概念。本文将探讨进阶技巧:从严格不可变性到 monad 和 functor 的运用。

\n\n

不可变性与不可变结构的运用

\n\n

不可变是 FP 的基石。在 TypeScript 中,我们可以通过 readonly 修饰符和实用类型在类型层面保证这一点。

\n\n
// 通过 ReadonlyDeep 实现深度不可变\ntype DeepReadonly<T> = {\n  readonly [P in keyof T]: DeepReadonly<T[P]>;\n};\n\ninterface User {\n  name: string;\n  address: { city: string; zip: number };\n}\n\nconst user: DeepReadonly<User> = {\n  name: "Alice",\n  address: { city: "Moscow", zip: 101000 }\n};\n\n// user.address.city = "SPb"; // 错误!属性是只读的
\n\n

对于安全的数据更新,请使用返回新对象的纯函数:

\n\n
function updateZip(user: DeepReadonly<User>, newZip: number): DeepReadonly<User> {\n  return { ...user, address: { ...user.address, zip: newZip } };\n}\n\nconst updatedUser = updateZip(user, 190000);
\n\n

函数组合与柯里化

\n\n

组合允许我们通过简单的函数构建出复杂的变换。在 TypeScript 中,利用泛型,我们可以创建类型安全的组合子。

\n\n
// 组合两个函数的类型\ntype Compose<A, B, C> = (f: (b: B) => C, g: (a: A) => B) => (a: A) => C;\n\nconst compose: Compose<any, any, any> = (f, g) => (x) => f(g(x));\n\n// 示例:将字符串转换为数字并加 1\nconst toNumber = (s: string): number => parseInt(s, 10);\nconst increment = (n: number): number => n + 1;\n\nconst parseAndIncrement = compose(increment, toNumber);\nconsole.log(parseAndIncrement("5")); // 6
\n\n

柯里化将多参数函数转换为一系列单参数函数。这使得组合更加灵活:

\n\n
// 带类型的通用柯里化函数\nfunction curry<T1, T2, R>(fn: (a: T1, b: T2) => R): (a: T1) => (b: T2) => R {\n  return (a: T1) => (b: T2) => fn(a, b);\n}\n\nconst add = (a: number, b: number): number => a + b;\nconst curriedAdd = curry(add);\nconst add5 = curriedAdd(5);\nconsole.log(add5(3)); // 8
\n\n

Functor 与 Monad:上下文操作

\n\n

Functor 是一种支持 map 操作的数据结构。在 TypeScript 中,数组、Promise 或自定义类型都可以成为 functor。

\n\n
// 用于安全处理 null/undefined 的 Option (Maybe) functor\ninterface Option<T> {\n  map<U>(fn: (value: T) => U): Option<U>;\n  getOrElse(defaultValue: T): T;\n}\n\nclass Some<T> implements Option<T> {\n  constructor(private value: T) {}\n  map<U>(fn: (value: T) => U): Option<U> {\n    return new Some(fn(this.value));\n  }\n  getOrElse(_: T): T {\n    return this.value;\n  }\n}\n\nclass None<T> implements Option<T> {\n  map<U>(_: (value: T) => U): Option<U> {\n    return new None<U>();\n  }\n  getOrElse(defaultValue: T): T {\n    return defaultValue;\n  }\n}\n\n// 使用示例\nconst maybeNumber: Option<number> = new Some(42);\nconst result = maybeNumber.map(x => x * 2).getOrElse(0); // 84
\n\n

Monad 在 functor 的基础上扩展了 flatMap(或 bind

博客

书籍推荐