如何使用命名参数来处理函数?

时间:2019-05-03 18:47:32

标签: javascript

让我们说我有一些这样的代码,

const createLogger = ({
  dispatch,
  frame,
  level,
  message,
}) => {
  dispatch(
    actions.debugLog.push({
      frame,
      level,
      message,
    }),
  )
}

如何在保留命名参数的同时使用此函数?

并像

一样使用它
const userLogger = createLogger({
    dispatch: useDispatch(), 
    frame: "userController",
    level: "Warning"
    // ...potentially other top level keys
})


// user stuff happens

userLogger({ message: "User deleted profile" })()

// later 

const adminUserLogger = userLogger({ 
    frame: "adminUserController",
    dispatch: adminDispatch
})

用例是这将在我的应用程序的某些区域中调用,从而减少了重复的代码。

期望值会增加(上面只是一个例子),但我也想覆盖某些键。假设我使用一组特定的预设键调用该函数,我想保留这些预设键,但是这次有了一个新的area。对于更复杂的部分(用于curry的标准用例),此排列的增加。

2 个答案:

答案 0 :(得分:0)

(假设您的“工厂功能”(createLogger)返回一个功能(log),调用者随后使用该功能记录事件,然后将其称为createLogFunction )。

(使用TypeScript):

type UseDispatch = 'auto' | true | false;
type Level       = 'Warning' | 'Error';

// This interface has all the required and optional named parameters of the original `actions.debugLog.push` function:
interface LogOptions {
    readonly dispatch: UseDispatch;
    readonly frame: string;
    readonly level: Level;
    readonly message: string;
    [propName: string]: any;
}

type LogFunction = ( opts: Partial<LogOptions> ) => void;
declare actions.debugLog.push: LogFunction; // so `actions.debugLog.push` has the type `LogFunction`.

// This function accepts a subset of `LogOptions` values and returns a new log function that also accepts a subset of LogOptions named parameters
function createLogFunction( factoryOpts: Partial<LogOptions>, innerLogFunc: LogFunction ): LogFunction {

    return function( invokeOpts: Partial<LogOptions> ): void {
        let combinedOptions: Partial<LogOptions> = {};
        combinedOptions = Object.assign( combinedOptions, factoryOpts );
        combinedOptions = Object.assign( combinedOptions, invokeOpts );

        innerLogFunc( combinedOptions );
    };
}

然后您可以像这样使用它:

let originalLogFunction: LogFunction = actions.debugLog.push;
originalLog( { message: "foo", level: 'Warning', dispatch: 'auto' } );

let logWarning = createLogFunction( { level: 'Warning', dispatch: 'auto' }, originalLogFunction );
logWarning( { message: "bar" } );

let noDispatchWarning = createLogFunction( { dispatch: false }, logWarning );
noDispatchWarning ( { message: "qux" } );

答案 1 :(得分:0)

采用slebetman's answer to "How to curry a function across an unknown number of parameters"的基本结构,并合并对象而不是添加数字:

const createLogFunction = options => {
  function curryingLogFunction(newOptions) {
    if (newOptions !== undefined) {
      // add newOptions into options
      options = { ...options, ...newOptions };

      return curryingLogFunction;
    }

    // dispatch isn't part of the object pushed to debugLog, so get a
    // version of options that doesn't include it
    const { dispatch: _, ...optionsWithoutDispatch } = options;

    // for the snippet
    console.log(options.dispatch, optionsWithoutDispatch);
    //options.dispatch(
    //  actions.debugLog.push(optionsWithoutDispatch),
    //);
  }
  return curryingLogFunction;
}

const logUserAction = createLogFunction({
  dispatch: 'useDispatch()', // string for the snippet, function in your code
  frame: "userController",
  level: "Warning"
  // ...potentially other top level keys
});


// user stuff happens

logUserAction({
  message: "User deleted profile"
})();

// later 

const logAdminAction = createLogFunction({
  frame: "adminUserController",
  dispatch: 'adminDispatch'
});

logAdminAction({ message: 'message' })({ currying: 'works' })({ frame: 'override defaults' })()