import _ from "lodash" // satisfies instanceof,val is Type export type req_t = (fun: string, ...argArray: any[]) => Promise<any> export type res_t<T extends object> = { [K in keyof T]: T[K] extends (fun: string, ...argArray: any[]) => Promise<infer R> ? R : never }[keyof T] export function callObjProxy<T>(req: req_t): T { function proxy2(prevPath: string[]): any { return new Proxy(() => { }, { get(target, propKey) { if (typeof propKey !== 'string') { return undefined } const next = [...prevPath, propKey] return proxy2(next); }, apply(target, thisArg, argArray) { const fun = prevPath.join( '.') return req(fun, ...argArray); } }); } return proxy2([]) as T; } export interface callObjSend_t { catch(str: string): void } export async function callObj<T extends Record<string, any>>(binObj: T, ...args: any[]) { function sendErrmsg(str: string) { return ["catch", str] } try { const [funpath, ...funParams] = args || [] console.log("callObj", ...args) if (typeof funpath !== "string") { return sendErrmsg("callObj funpath不是string") } // 1. 解析路径 const p = funpath.replace(/[\[\]]/g, '.').split('.').filter(Boolean); if (p.length === 0) { return sendErrmsg("callObj 路径不存在") } // 2. 获取方法 const fun = _.get(binObj, p); if (typeof fun !== "function") { return sendErrmsg(`callObj 指定路径不是函数: ${funpath}`) } // 3. 获取方法的直接父对象(this 上下文) const parentPath = p.slice(0, -1); const context = parentPath.length > 0 ? _.get(binObj, parentPath) : binObj; if (context == null) { return sendErrmsg(`callObj 方法上下文不存在: ${funpath}`) } // 4. 正确执行 // console.log("callObj", { funpath, funParams }) const data = await fun.apply(context, funParams); // const data = await fun(...funParams); //Cannot read properties of undefined (reading 'broModules') return data } catch (err) { // console.log("callObj error", { funpath, funParams, err }) if (isError(err)) { return sendErrmsg(err.message) } else { return sendErrmsg("callObj未知错误".concat(String(err))) } } }
import _ from "lodash" // satisfies instanceof,val is Type export type req_t = (fun: string, ...argArray: any[]) => Promise<any> export type res_t<T extends object> = { [K in keyof T]: T[K] extends (fun: string, ...argArray: any[]) => Promise<infer R> ? R : never }[keyof T] export function callObjProxy<T>(req: req_t): T { function proxy2(prevPath: string[]): any { return new Proxy(() => { }, { get(target, propKey) { if (typeof propKey !== 'string') { return undefined } const next = [...prevPath, propKey] return proxy2(next); }, apply(target, thisArg, argArray) { const fun = prevPath.join( '.') return req(fun, ...argArray); } }); } return proxy2([]) as T; } export interface callObjSend_t { catch(str: string): void } export async function callObj<T extends Record<string, any>>(binObj: T, ...args: any[]) { function sendErrmsg(str: string) { return ["catch", str] } try { const [funpath, ...funParams] = args || [] console.log("callObj", ...args) if (typeof funpath !== "string") { return sendErrmsg("callObj funpath不是string") } // 1. 解析路径 const p = funpath.replace(/[\[\]]/g, '.').split('.').filter(Boolean); if (p.length === 0) { return sendErrmsg("callObj 路径不存在") } // 2. 获取方法 const fun = _.get(binObj, p); if (typeof fun !== "function") { return sendErrmsg(`callObj 指定路径不是函数: ${funpath}`) } // 3. 获取方法的直接父对象(this 上下文) const parentPath = p.slice(0, -1); const context = parentPath.length > 0 ? _.get(binObj, parentPath) : binObj; if (context == null) { return sendErrmsg(`callObj 方法上下文不存在: ${funpath}`) } // 4. 正确执行 // console.log("callObj", { funpath, funParams }) const data = await fun.apply(context, funParams); // const data = await fun(...funParams); //Cannot read properties of undefined (reading 'broModules') return data } catch (err) { // console.log("callObj error", { funpath, funParams, err }) if (isError(err)) { return sendErrmsg(err.message) } else { return sendErrmsg("callObj未知错误".concat(String(err))) } } }
import _ from "lodash"
// satisfies instanceof,val is Type
export type req_t = (fun: string, ...argArray: any[]) => Promise<any>
export type res_t<T extends object> = {
[K in keyof T]: T[K] extends (fun: string, ...argArray: any[]) => Promise<infer R> ? R : never
}[keyof T]
export function callObjProxy<T>(req: req_t): T {
function proxy2(prevPath: string[]): any {
return new Proxy(() => { }, {
get(target, propKey) {
if (typeof propKey !== 'string') {
return undefined
}
const next = [...prevPath, propKey]
return proxy2(next);
},
apply(target, thisArg, argArray) {
const fun = prevPath.join( '.')
return req(fun, ...argArray);
}
});
}
return proxy2([]) as T;
}
export interface callObjSend_t {
catch(str: string): void
}
export async function callObj<T extends Record<string, any>>(binObj: T, ...args: any[]) {
function sendErrmsg(str: string) {
return ["catch", str]
}
try {
const [funpath, ...funParams] = args || []
console.log("callObj", ...args)
if (typeof funpath !== "string") {
return sendErrmsg("callObj funpath不是string")
}
// 1. 解析路径
const p = funpath.replace(/[\[\]]/g, '.').split('.').filter(Boolean);
if (p.length === 0) {
return sendErrmsg("callObj 路径不存在")
}
// 2. 获取方法
const fun = _.get(binObj, p);
if (typeof fun !== "function") {
return sendErrmsg(`callObj 指定路径不是函数: ${funpath}`)
}
// 3. 获取方法的直接父对象(this 上下文)
const parentPath = p.slice(0, -1);
const context = parentPath.length > 0
? _.get(binObj, parentPath)
: binObj;
if (context == null) {
return sendErrmsg(`callObj 方法上下文不存在: ${funpath}`)
}
// 4. 正确执行
// console.log("callObj", { funpath, funParams })
const data = await fun.apply(context, funParams);
// const data = await fun(...funParams); //Cannot read properties of undefined (reading 'broModules')
return data
} catch (err) {
// console.log("callObj error", { funpath, funParams, err })
if (isError(err)) {
return sendErrmsg(err.message)
} else {
return sendErrmsg("callObj未知错误".concat(String(err)))
}
}
}

用户359687679
12月29日
|
浏览 48
这段代码实现了一个动态代理调用机制,允许通过字符串路径调用对象的方法。以下是关键点分析:
核心功能
-
callObjProxy<T>(req)- 创建类型安全的代理对象- 使用 Proxy 拦截属性和方法调用
- 将链式调用转换为点分隔的字符串路径
- 最终通过
req函数执行远程调用
-
callObj(binObj, ...args)- 执行实际的方法调用- 解析字符串路径(支持
a.b.c或a[b].c格式) - 使用 lodash 的
_.get安全获取嵌套方法 - 正确绑定
this上下文到方法的父对象
- 解析字符串路径(支持
主要问题与改进建议
1. 类型安全性问题
复制代码
// 当前:any 类型过多
export type req_t = (fun: string, ...argArray: any[]) => Promise<any>
// 建议:增加泛型约束
export type req_t<Args extends any[] = any[], R = any> =
(fun: string, ...args: Args) => Promise<R>
2. 错误处理优化
复制代码
// 当前:返回数组格式的错误
return ["catch", str]
// 建议:统一错误响应格式
export type CallResult<T = any> =
| { success: true; data: T }
| { success: false; error: string }
export async function callObj<T extends Record<string, any>, R = any>(
binObj: T,
...args: any[]
): Promise<CallResult<R>> {
// ... 实现
}
3. 性能优化
- 避免重复路径解析,可缓存解析结果
- 考虑使用
Reflect.get替代_.get减少依赖
4. 安全性增强
复制代码
// 添加路径白名单验证
const allowedPaths = ['api.', 'service.']; // 示例白名单
if (!allowedPaths.some(prefix => funpath.startsWith(prefix))) {
return sendErrmsg("访问路径未授权");
}
使用示例
复制代码
// 定义接口
interface ApiService {
user: {
getInfo(id: number): Promise<UserInfo>;
update(data: UserData): Promise<void>;
}
}
// 创建代理
const api = callObjProxy<ApiService>(async (path, ...args) => {
return await callObj(actualService, path, ...args);
});
// 类型安全调用
const userInfo = await api.user.getInfo(123);
注意事项
- Proxy 在严格模式下可能影响性能
- 路径解析需确保与后端约定一致
- 考虑添加调用超时和重试机制
如需继续排查,请点击下方【🔍追问按钮】提交补充信息
我要提问
复制内容
分享给好友
AI编程问答网 免责声明:
以上内容除特别注明外均来源于网友提问,AI编程问答网回答,权益归原著者所有;
下一篇:你是谁
