typescript 动态函数返回值类型typing 定义问题
目前的诉求是 想整个工具函数 把一般的业务函数包一层,业务函数成功执行就返回相应的返回值,如果中间报错了就吞掉错误 返回一个默认值 在javascript里 实现算是满足要求的 代码如下
const assert = require('assert');
function safeCall(fn, defaultValue) {
defaultValue = defaultValue || null;
return function realCall(thisCall, ...args){
try {
return fn.call(thisCall, ...args);
} catch (e) {
return defaultValue;
}
};
}
function safeAsyncCall(fn, defaultValue) {
defaultValue = defaultValue || null;
return async function realCall(thisCall, ...args) {
try {
return await fn.call(thisCall, ...args);
} catch (e) {
return Promise.resolve(defaultValue);
}
};
}
// example
const saveJsonParse = safeCall(JSON.parse, { token: null });
const res1 = saveJsonParse(null , '{"token":123}');
const res2 = saveJsonParse(null , '{"token`:888888}');
assert.deepStrictEqual(res1, {token: 123});
assert.deepStrictEqual(res2, {token: null});
async function remoteUnSafeCall(a) {
if (a) {
return a;
}
throw new Error('not ok')
}
const thisSafeCall = safeAsyncCall(remoteUnSafeCall, null);
thisSafeCall(null, false).then((a) => assert.strictEqual(a, null))
thisSafeCall(null, 2).then((a) => assert.strictEqual(a, 2))
但是在ts 环境中 这种动态的函数 就不能享受typing 的约束 有点尴尬 想着用typing 限制输入输出
在ts 的文档中找到了工具的类型 Parameters<T>
和 ReturnType<T>
然后是类似这样处理
function safeCall<T extends Function >(fn: T, defaultValue: any) {
defaultValue = defaultValue || null;
return function realCall(thisCall, ...args: Parameters<typeof fn>): typeof defaultValue | ReturnType<typeof fn> {
try {
return fn.call(thisCall, ...args);
} catch (e) {
return defaultValue;
}
};
}
// use
function sampleCall( params: { a: number; b: string; c: number} ): string {
return "ddddd";
}
const finalFn = safeCall(sampleCall, "5");
const res1 = finalFn(null, { a: 1}); // IDE 会有提示 表示输入的参数有问题
const res = finalFn(null, { a: 1, b: '12', c: 12});
res / 10; // 但是输出的这种错误用法不会报错
尝试这样写之后 除了上面的返回值无法限定 之外 执行的时候 还会报编译错误 搜了下发现 ts认为Function的调用属性不安全 所以加以限制了 然后不得已 定义了个normalFn 的类型 类似:
type NormalFn = (...arg) => any;
function safeCall<T extends NormalFn >(fn: T, defaultValue: any) {
defaultValue = defaultValue || null;
return function realCall(thisCall, ...args: Parameters<typeof fn>): typeof defaultValue | ReturnType<typeof fn> {
try {
return fn.call(thisCall, ...args);
} catch (e) {
return defaultValue;
}
};
}
function sampleCall( params: { a: number; b: string; c: number} ): string {
return "ddddd";
}
const d = safeCall(sampleCall, "5");
let f = d(null, { a: 1, b: '12', c: 12});
f / 10; // 但是输出的这种错误用法不会报错
这次到是不报错了 但是最后的返回值的类型还是没有限制住。。。 有点不知道如何改动了 搜索也不知道用啥关键词 大家有什么想法吗
2 回复
const call = <T extends (...args: any) => any, U>(fn: T, dv: U): ReturnType<T> | U => {
try {
return fn();
} catch (e) {
return dv;
}
};
const fn1 = () => 1;
const fn2 = () => 'string';
const run = () => {
const v1 = call(fn1, true);
// const v1: number | true
const v2 = call(fn2, undefined);
// const v2: string | undefined
};
哦哦 我懂了 是我前面的 defaultValue 设置成 any 了 所以后面的 typeof defaultValue | ReturnType<typeof fn> 就限制不住了 犯了个低级错误。。。 多谢~ @noe132