Typescript 是否可以执行运行时类型检查以确定属性是否是具有特定调用签名和返回类型的函数?

Typescript 是否可以执行运行时类型检查以确定属性是否是具有特定调用签名和返回类型的函数?,typescript,Typescript,我是学习打字脚本的新用户。是否可以执行运行时类型检查以确定属性是否是具有特定调用签名和返回类型的函数 函数是CourseAction(action:any):action是CourseAction{ const FunctionType='function'; 试一试{ //检查定义的预期属性和预期类型 if(!action.success&&typeof action.success!==FunctionType){ 返回false; }如果(!action.request&&typeof a

我是学习打字脚本的新用户。是否可以执行运行时类型检查以确定属性是否是具有特定调用签名和返回类型的函数

函数是CourseAction(action:any):action是CourseAction{
const FunctionType='function';
试一试{
//检查定义的预期属性和预期类型
if(!action.success&&typeof action.success!==FunctionType){
返回false;
}如果(!action.request&&typeof action.request!==FunctionType),则为else{
返回false;
}else if(!action.failure&&typeof action.failure!==FunctionType){
返回false;
}
//除了尝试调用请求之外,这里还有success和failure函数
//还有catch exception有没有更快的方法来检查函数是否
//预期的呼叫签名?
}捕捉(错误){
返回false;
}
返回true;
}

创建了一个类型脚本

您可以使用内置类型
函数
并定义如下类型保护:

function isFunction(p: any): p is Function{
  return typeof p === "function"  
}

函数也是对象,因此对象函数具有属性和方法(应用、绑定)。其中一个属性是-
name
,对于命名函数,它将是一个带有函数名的字符串,对于匿名函数,它将是空字符串

如果要传递已命名的函数,则此属性可用于在运行时区分特定函数。考虑:

// two named functions as an example
const f1 = (arg1: string) => {
    // body
}
const f2 = (arg1: number) => {
    // body
}

function main(obj: {name: string, payload: Function | string}) {
    if (typeof obj.payload === 'function' && obj.payload.name === 'f1') {
        // it is f1 function 
    }
    if (typeof obj.payload === 'function' && obj.payload.name === 'f2') {
        // it is f2 function 
    }
}
我们还可以通过类型防护装置和类型规格在类型级别上更安全:

const f1 = (arg1: string) => {
    // body
}
const f2 = (arg1: number) => {
    // body
}

const isF1 = (a: unknown): a is typeof f1 => typeof a === 'function' && a.name === 'f1'; 
const isF2 = (a: unknown): a is typeof f2 => typeof a === 'function' && a.name === 'f2'; 

function main(obj: {name: string, payload: typeof f1 | typeof f2 | string}) {
    if (isF1(obj.payload)) {
        obj.payload // it is f1 on type level also
    }
    if (isF2(obj.payload)) {
        obj.payload // it is f2 on type level also
    }
}

不幸的是,您无法在运行时判断函数是否匹配TS签名。我将使用您的函数签名示例,如下所示:

type ActionCallback = (arg1: string, arg2: string) => PayloadAction;
function testFunc(x: any): x is (a: string, b: string) => PayloadAction {
  if (typeof x !== "function") return false;
  const ret = x("", ""); // actually call function
  return typeof ret.actionType === "string" && typeof ret.actionPayload === "string";
}

function isCourseAction(action: any): action is CourseAction {
  return (["success", "request", "failure"].every(k => testFunc(action[k])));
}
如您所知,您可以通过简单的
typeof
检查来检查值
fn
是否是函数。在那之后,你很快就没有合理的选择了。您可以尝试检查
fn.length
,以获取函数在JavaScript中所需的参数数,但这是脆弱的:

const normal: ActionCallback = (x, y) => ({ actionType: x, actionPayload: y });
console.log(normal.length); // 2
const fewer: ActionCallback = (x) => normal(x, x);
console.log(fewer.length); // 1
const evenFewer: ActionCallback = (...[x, y]) => normal(x, y);
console.log(evenFewer.length); // 0
const more: ActionCallback = (x: string, y: string, z?: string) => normal(x, z ? z : y);
console.log(more.length); // 3
所有这些函数都满足
ActionCallback
契约,但它们在运行时具有不同的
length
属性


显然,正如您所暗示的,您可以继续在一些测试输入上调用函数,并使用结果作为验证函数的指南,如下所示:

type ActionCallback = (arg1: string, arg2: string) => PayloadAction;
function testFunc(x: any): x is (a: string, b: string) => PayloadAction {
  if (typeof x !== "function") return false;
  const ret = x("", ""); // actually call function
  return typeof ret.actionType === "string" && typeof ret.actionPayload === "string";
}

function isCourseAction(action: any): action is CourseAction {
  return (["success", "request", "failure"].every(k => testFunc(action[k])));
}
这将是一种工作。。。虽然这也不完美,;对于测试输入,一个特别奇怪的函数可能会返回一些合理的结果,但对于其他输入,则返回完全不同的结果:

function ohComeOn(x: string, y: string) {
  if (!x && !y) return { actionType: "normal", actionPayload: "all perfectly normal" };
  return 12345;
}
const why = { success: ohComeOn, request: ohComeOn, failure: ohComeOn }
console.log(isCourseAction(why)); // true
console.log(why.request("other", "input")); // 12345, not a PayloadAction at all!
在实践中,我不会太担心这个异常(我的意思是,有人可能会给你一个专门设计的通过测试的方法,但当你使用它时失败)。但是,如果您不想调用函数来测试它,那么您可能会运气不佳


无论如何,希望这有帮助;祝你好运


谢谢@Eldar,是否可以检查函数是否有一组特定的参数和返回类型?除非您将这些属性添加到函数中,否则不可能,函数是一个对象,这样你就可以解决问题了that@anon_dcs3spp您可以使用
ReturnType
提取返回类型,使用
parameters
提取参数类型,但我不确定您是否可以将它们用作TypeGuard。此代码似乎不是,因为
CourseAction
未在任何位置定义,
(!action.success&&typeof action.success!==“function”)
似乎是一个奇怪的测试,因为如果
action.success
是错误的,那么
类型的操作。success
肯定不是
“function”
(JavaScript中没有错误的函数)您不需要测试它。您无法在运行时判断函数是否与TS签名匹配。您可以检查
fn.length
以获取函数在JavaScript中期望的参数数,但即使是这样,我也不会尝试。我想您需要一些启发,但我需要一个适当的建议。感谢@jcalz添加了到typescrip的链接t playground好的,至少你应该正确地测试
“function”
,而你没有这样做,请参阅
console.log(isCourseAction({success:'oops',request:'oops',failure:'oops});//true
。但这实际上只是你的一个错误,不是问题的答案,所以你能先解决它吗?(可能将
&
更改为
| |
?)为@jcalz干杯,更新…非常感谢@jcalz的帮助和示例,非常感谢:)好的,看来最好的希望是测试函数的类型,也许用测试输入调用函数。。。。