1

我想和你分享一个编码挑战,希望有人也被这个挑战所吸引,并且可以提供帮助,因为它需要一些“高级”的 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功能,以便...

  1. 您可以通过函数的callback参数提供任务的实际实现createTask
  2. 所有自定义参数都应该可以使用yargs包中的 awesome api 进行配置
  3. 如果您使用错误的参数执行任务,打字稿编译器会警告您

修订版 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 调用中自动推断类型。我希望有人能帮帮忙 :)

谢谢!

4

0 回答 0