我想和你分享一个编码挑战,希望有人也被这个挑战所吸引,并且可以提供帮助,因为它需要一些“高级”的 Typescript 技能:) 首先是一些基本的 Javascript,以明确我想要做什么:
// create a custom Task using a custom, configurable creator function
// 'createTask' should be a higher-order function returning the actual task function
const customTask = createTask( /* Some configuration parameters should go here */);
// now we should be able to execute the task with some custom arguments
const result = customTask( { foo: true} );
挑战是实现该createTask
功能,以便...
- 您可以通过函数的
callback
参数提供任务的实际实现createTask
- 所有自定义参数都应该可以使用yargs包中的 awesome api 进行配置
- 如果您使用错误的参数执行任务,打字稿编译器会警告您
修订版 1 - 没有类型检查
现在让我们忽略类型检查问题。
所以在普通的javascript中应该是这样的:
function createTask(callback, parameterConfiguration) {
return function(customArgs) {
// TODO: make sure that only valid args are passed to the callback. (using parameterConfiguration)
// execute the task with custom arguments
return callback(customArgs);
};
}
// We should be able to use the yargs api to configure which parameters our task should have:
const parameterConfiguration = require('yargs').option('foo', { type: 'boolean' });
// now we create our task with:
const customTaskWithFoo = createTask(callback, parameterConfiguration);
// callback function which does the actual meaningful work
function callback(customArgsWithFoo) {
const { foo } = customArgsWithFoo;
console.log('executing with args:', { foo });
}
// later we should be able to execute the task with values for all configured parameters:
customTaskWithFoo({ foo: true });
修订版 2 - 基本类型检查
现在让我们用打字稿写这个:
import { Argv } from 'yargs'
export type CustomTask<Params, Return> = (args: Params) => Return
export type CustomTaskCallback<Params, Return> = (args: Params) => Return
export function createTask<Params, Return>(callback: CustomTaskCallback<Params, Return>, parameterConfiguration: Argv<Params>): CustomTask<Params, Return> {
return function(customArgs: Params) {
const argsFromYargs = parameterConfiguration.argv
const actualArgs = {
...argsFromYargs,
...customArgs
}
return callback(actualArgs)
}
}
const customTaskWithFoo = createTask(callback, require('yargs').option('foo', { type: 'boolean' }))
// callback function which does the actual meaningful work
function callback(customArgsWithFoo): void {
const { foo } = customArgsWithFoo
console.log('executing with args:', { foo })
}
// execute the task. Works as expected. No compiler errors
customTaskWithFoo({ foo: false })
// Now this should be permitted by the typescript compiler,
// because the `foo` parameter was configured to be a `boolean`
// using the yargs api before with `.option('foo', { type: 'boolean' })`
// Unfortunately this is actually not rejected by the compiler.
customTaskWithFoo({ foo: 'string-value' })
现在要按预期进行这项工作,我想我需要使用一些更复杂的打字稿魔法。
修订版 3 - 几乎完美,但具有冗余类型信息
我想我已经很接近了,因为当我明确地为customTask
变量提供类型时它可以工作:
// customTask with explicit type:
let customTask: CustomTask< {foo:boolean}, void>
customTask = createTask(callback, require('yargs').option('foo', { type: 'boolean' }))
// now this is rejected as expected:
customTask({ foo: 'string-value' })
我只是不满意必须foo
在 2 个地方编写类型:变量声明中let customTask: CustomTask<{**foo:boolean**}, void>
的第一个和 yargs api 调用中的第二个.option( 'foo', { **type: 'boolean'** } )
我相信有一些高级打字稿功能允许编译器customTask
从 yargs 的 api 调用中自动推断类型。我希望有人能帮帮忙 :)
谢谢!