TypeScript 获取函数的参数类型、返回值类型

事例:

function test(lzwme: string, idx: number) {
  return {
    lzwme,
    idx,
  };
}

1 获取函数的参数类型

使用预定义的 Parameters 可以获取到一个函数的参数类型列表。
获取 test 函数的参数类型:

type TestArgsType = Parameters<typeof test>;
// TestArgsType => [lzwme: string, idx: number]

获取 idx 参数的类型:

type TestArgsType = Parameters<typeof test>[1];
// TestArgsType => idx: number

我们看一下 Parameters 的定义:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

我们可以看到,其实它主要是通过 infer P 获取到 T 的参数类型列表 P 并返回,如果 T 不是函数则返回 never

2 获取函数的返回值类型

使用预定义的 ReturnType 可以获取到一个函数的参数类型列表。

获取 test 函数的返回值类型:

type TestReturnType = ReturnType<typeof test>;

我们再看一下 ReturnType 的定义:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

Parameters 十分类似,不同的是通过 infer R 获取并返回 T 的返回值类型。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
A: 可以借助ts-node实现动态加载ts文件。具体代码如下: ```typescript import * as ts from 'typescript'; import * as fs from 'fs'; import * as path from 'path'; interface FunctionParam { name: string; type?: string; required?: boolean; } interface Function { name: string; params?: FunctionParam[]; returnType?: string; } function loadModule(modulePath: string, functionName: string): Function { const code = fs.readFileSync(modulePath).toString(); const sourceFile = ts.createSourceFile(modulePath, code, ts.ScriptTarget.ESNext); const functionDeclaration = sourceFile.statements.find((node) => { if (!ts.isFunctionDeclaration(node)) { return false; } return node.name?.escapedText === functionName; }) as ts.FunctionDeclaration; const functionParams = functionDeclaration.parameters.map((parameter) => { const parameterSymbol = sourceFile.locals.get((parameter.name as ts.Identifier).escapedText); const parameterType = parameter.type ? code.slice(parameter.type.pos, parameter.type.end) : undefined; const parameterRequired = !(parameterQuestionToken && parameterQuestionToken.token === ts.SyntaxKind.QuestionToken); return { name: (parameter.name as ts.Identifier).escapedText.toString(), type: parameterType, required: parameterRequired, }; }); const returnTypeSymbol = functionDeclaration.symbol?.declarations?.[0]?.type; const returnType = returnTypeSymbol ? code.slice(returnTypeSymbol.pos, returnTypeSymbol.end) : undefined; return { name: functionName, params: functionParams, returnType, }; } function invokeFunction(functionModule: string, functionName: string, params: any[]): any { const modulePath = path.resolve(__dirname, functionModule); const functionObject = loadModule(modulePath, functionName); // 校验参数个数 if (params.length !== (functionObject.params?.length ?? 0)) { throw new Error('参数个数不匹配'); } const paramObject: Record<string, any> = {}; functionObject.params?.forEach((param, index) => { const paramValue = params[index]; // 检验参数是否必须 if (param.required && paramValue === undefined) { throw new Error(`参数${param.name}不能为空`); } // 检验参数类型 if (param.type && typeof paramValue !== param.type) { throw new Error(`参数${param.name}类型不正确,期望为${param.type}`); } paramObject[param.name] = paramValue; }); const functionPath = `${modulePath}#${functionName}`; const functionResult = invokeFunctionCache.getOrCreate(functionPath, () => { const functionModule = require(modulePath); const functionReference = functionModule[functionName] || functionModule.default || functionModule; return functionReference(...params); }); // 检验返回值类型 if (functionObject.returnType && typeof functionResult !== functionObject.returnType) { throw new Error(`返回值类型不正确,期望为${functionObject.returnType}`); } return functionResult; } interface InvokeFunctionCacheEntry { result: any; timestamp: number; } class InvokeFunctionCache { private readonly cache: Record<string, InvokeFunctionCacheEntry> = {}; private readonly timeout: number; constructor(timeout?: number) { this.timeout = timeout ?? 5000; } public getOrCreate(key: string, createFunc: () => any): any { const cachedEntry = this.cache[key]; const currentTime = Date.now(); if (cachedEntry && currentTime - cachedEntry.timestamp < this.timeout) { return cachedEntry.result; } else { const result = createFunc(); this.cache[key] = { result, timestamp: currentTime }; return result; } } } const invokeFunctionCache = new InvokeFunctionCache(); ``` ```json [ { "functionModule": "./function1.ts", "functionName": "function1", "args": [ 1, 2 ] }, { "functionModule": "./function2.ts", "functionName": "function2", "args": [ "hello" ] }, ] ``` ```typescript type Args = unknown[]; interface JsonFunction { functionModule: string; functionName: string; args: Args; } function main(jsonFunctions: JsonFunction[]): void { for (const jsonFunction of jsonFunctions) { const {functionModule, functionName, args} = jsonFunction; try { const result = invokeFunction(functionModule, functionName, args); console.log(`执行 ${functionName}(${args.join(', ')}) 结果为 ${result}`); } catch (err) { console.error(`执行 ${functionName}(${args.join(', ')}) 失败,原因为 ${err.message}`); } } } const jsonFunctions: JsonFunction[] = [ { functionModule: './function1.ts', functionName: 'function1', args: [1, 2], }, { functionModule: './function2.ts', functionName: 'function2', args: ['hello'], }, ]; main(jsonFunctions); ``` 在该代码中,我们通过loadModule函数加载ts文件,并从中获取需要执行的函数参数数量和返回值类型等信息。然后,我们通过invokeFunction函数来执行函数,并做出必要的参数返回值类型检查。最后,我们利用invokeFunctionCache来缓存函数的执行结果,以加快函数的重复执行速度。 最后,我们可以通过调用main函数来执行由JSON序列化的函数调用列表。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值