@fengmk2 感谢大佬回复,下面是我的一个现状还原和实现的过程:
在项目配置文件中添加一个symbol指向的自定义配置(SYMBOL_PERMISSION):
// config/config.local.ts
import { EggAppConfig, PowerPartial } from 'egg';
import { SYMBOL_PERMISSION } from '../utils/constants'; // export const SYMBOL_PERMISSION = Symbol('Middleware#permission');
export default (appInfo) => {
    const config: PowerPartial<EggAppConfig> = {};
    config.security = {
        csrf: {
            enable: false,
            ignoreJSON: true,
        },
        domainWhiteList: ['*']
    };
    const bizConfig = {
        permission: {
            enable: true,
            whitelist: ['simpul']
        },
        // 自定义配置
        [SYMBOL_PERMISSION]: {
            permission: {
                msg: 'local',
                author: 'simpul'
            }
        }
    };
    return {
        ...config,
        ...bizConfig,
    };
};
期望在我自己实现的中间件permission中访问到对应配置项,但是结果返回undefined:
// app/middleware/permission.ts
import { Context } from 'egg';
import { SYMBOL_PERMISSION } from '../../utils/constants';
export default function permission(): any {
    return async (ctx: Context, next: () => Promise<any>) => {
        const config = ctx.app.config.permission;
        console.log((ctx.app.config as any)[SYMBOL_PERMISSION]);// 这里ctx.app.config丢失SYMBOL_PERMISSION属性, 返回undefined
        if (config?.enable) {
            if (!config.whitelist.includes(ctx.user.nick)) {
                // 没有权限
                ctx.status = 403;
                ctx.body = {
                    code: 403,
                    message: 'You do not have permission',
                };
                return;
            }
        }
        return await next();
    };
}
发现需要补充extend2模块拷贝symbol的能力,这里我参考了lodash模块深拷贝的实现改了下源码:
// node_modules/extend2/index.js
'use strict';
var hasOwn = Object.prototype.hasOwnProperty;
var toStr = Object.prototype.toString;
var propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
var nativeGetSymbols = Object.getOwnPropertySymbols;
var isPlainObject = function isPlainObject(obj) {
  if (!obj || toStr.call(obj) !== '[object Object]') {
    return false;
  }
  var hasOwnConstructor = hasOwn.call(obj, 'constructor');
  var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
  // Not own constructor property must be Object
  if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
    return false;
  }
  // Own properties are enumerated firstly, so to speed up,
  // if last one is own, then all properties are own.
  var key;
  for (key in obj) { /**/ }
  return typeof key === 'undefined' || hasOwn.call(obj, key);
};
var getSymbols = function getSymbols(object) {
  if (object == null) {
    return [];
  }
  object = Object(object);
  return nativeGetSymbols(object).filter((symbol) => propertyIsEnumerable.call(object, symbol))
}
var handleCopy = function handleCopy(target, options, name, deep) {
  var src, copy, clone;
  src = target[name];
  copy = options[name];
  // Prevent never-ending loop
  if (target === copy) return;
  // Recurse if we're merging plain objects
  if (deep && copy && isPlainObject(copy)) {
    clone = src && isPlainObject(src) ? src : {};
    // Never move original objects, clone them
    target[name] = extend(deep, clone, copy);
  // Don't bring in undefined values
  } else if (typeof copy !== 'undefined') {
    target[name] = copy;
  }
};
var extend = function extend() {
  var options, name;
  var target = arguments[0];
  var i = 1;
  var length = arguments.length;
  var deep = false;
  // Handle a deep copy situation
  if (typeof target === 'boolean') {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
  } else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) {
    target = {};
  }
  for (; i < length; ++i) {
    options = arguments[i];
    // Only deal with non-null/undefined values
    if (options == null) continue;
    // Extend the base object
    for (name in options) {
      if (name === '__proto__') continue;
      handleCopy(target, options, name, deep);
    }
    // handle symbol
    var symbols = getSymbols(options);
    for (const symbol of symbols) {
      handleCopy(target, options, symbol, deep);
    }
  }
  // Return the modified object
  return target;
};
module.exports = extend;
然后再次访问就发现可以拿到配置项了:
console.log((ctx.app.config as any)[SYMBOL_PERMISSION]); // { permission: { msg: 'local', author: 'simpul' } }