柯里化可分层固化请求配置:单层固定baseURL,两层追加token认证,三层封装get/post等语义方法;但需注意token刷新、调试难度及错误处理须手动实现。

直接用柯里化把 baseURL 提前“锁住”,后续所有接口只关心路径和参数,不用反复写域名或环境地址。
单层柯里化:固定基础 URL,生成环境专属请求函数
这是最常用、最轻量的用法。你不需要抽象出一整套 SDK,只需一个接收 baseUrl 的函数,返回另一个接收请求配置的函数:
const createAPI = (baseUrl) => (options) => {
const { method = 'GET', path = '', headers = {}, body } = options;
const url = `${baseUrl}${path}`;
return fetch(url, {
method,
headers: { 'Content-Type': 'application/json', ...headers },
body: method !== 'GET' && body ? JSON.stringify(body) : undefined
});
};
这样就能快速生成不同环境实例:
const devAPI = createAPI('https://api.dev.example.com')const prodAPI = createAPI('https://api.prod.example.com')
调用时干净利落:devAPI({ path: '/users', method: 'POST', body: { name: 'Alice' } })。注意:如果后端要求 Content-Type: text/plain 或其他类型,必须显式覆盖 headers,否则默认会覆盖掉。
两层柯里化:再固化认证头(如 Token)
当每个请求都带统一 Authorization,又不想在每次调用时重复传,可以加一层:
const createAuthedAPI = (baseUrl) => (token) => (options) => {
const { method = 'GET', path = '', headers = {}, body } = options;
const url = `${baseUrl}${path}`;
return fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
...headers
},
body: method !== 'GET' && body ? JSON.stringify(body) : undefined
});
};
使用方式变成:
const userAPI = createAuthedAPI('https://api.example.com')('user-token-abc123')userAPI({ path: '/profile' })
⚠️ 容易踩的坑:Token 过期后,userAPI 实例不会自动刷新——它只是闭包捕获了那一刻的值。需要配合 token 刷新逻辑手动重建实例,或把 token 改为函数(如 () => getActiveToken())再嵌一层。
三层柯里化:封装常用方法(get/post),语义更清晰
如果你发现团队总在写 method: 'GET' 这种重复字段,可以再拆一层,让调用像原生方法一样自然:
const createEndpoint = (baseUrl) => (token) => {
const request = (method) => (path) => (body) =>
fetch(`${baseUrl}${path}`, {
method,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: method !== 'GET' && body ? JSON.stringify(body) : undefined
});
return {
get: (path) => request('GET')(path)(undefined),
post: (path, body) => request('POST')(path)(body),
put: (path, body) => request('PUT')(path)(body)
};
};
调用就变成:createEndpoint('https://api.example.com')('xyz')?.get('/users')。这种写法适合模块内高频调用、且对可读性要求高的场景。但要注意:每多一层柯里化,调试时堆栈更深,错误定位更难;生产环境建议保留 source map 并避免无意义嵌套。
为什么不用 bind 或偏函数?
bind 能实现类似效果,但缺乏柯里化的“参数节奏感”:它不强制按顺序传参,也不天然支持分层复用。比如你想先固定 baseUrl,再根据不同模块注入不同 timeout 和 retry 策略,bind 就得靠参数位置硬记,而柯里化用函数名就能表达意图(withTimeout、withRetry)。另外,bind 返回的函数无法被 TypeScript 精准推导泛型类型,柯里化函数更容易写出类型安全的签名。
真正容易被忽略的是错误边界——柯里化本身不处理网络失败、超时、取消等,这些必须在最内层 fetch 调用前后显式包裹。别指望“锁住 baseURL”就能自动兜底,那只是配置起点,不是完整请求生命周期的替代品。


















