首页 > 解决方案 > 打字稿:从枚举值生成具有映射属性的对象

问题描述

我正在寻找一种方法来生成一个对象,该对象在编译期间从枚举值和预定义的函数调用中计算出的值 - 基本上这个想法是将函数的一些参数与键绑定。例如,假设我有以下内容:

enum LogLevel {
  error = 'error',
  warning = 'warning'
  info = 'info'
}

const log = (level: LogLevel, message: string) => {
  console.log(`Level: ${level}, Message: ${message}`);
}

我正在寻找如下语法:

const logger = {
  [level in LogLevel]: (msg: string) => log(level, msg)
}

这不起作用(编译失败A computed property name must be of type 'string', 'number', 'symbol', or 'any'.

我希望它在功能上等于:

const logger = {
  [LogLevel.error]: (msg: string) => log(LogLevel.error, msg),
  [LogLevel.warning]: (msg: string) => log(LogLevel.warning, msg),
  [LogLevel.info]: (msg: string) => log(LogLevel.info, msg)
}

这样我就可以这样使用它:

logger.error("Bad things happened")
logger.warn("Help me")

实际用例在枚举中包含许多元素,我宁愿在每次添加新元素时都不要修改对象。我知道我至少可以添加一个类型约束,该约束要求枚举中的所有键都以非常相似的语法出现在类型中:

type Logger = {
  [level in LogLevel]: (msg: string) => void
}

但由于这些值是重复的并且实际上只是样板文件,我希望它们能够自动生成。

标签: typescript

解决方案


这里唯一要记住的是,TypeScript类型在编译为 JavaScript 后会被剥离,因此您需要Logger动态生成。

const allLogLevels = ['error', 'warning', 'info'] as const;
type LogLevel = typeof allLogLevels[number]; // 'error' | 'warning' | 'info'

type Logger = {
  [level in LogLevel]: (msg: string) => void
}

const log = (level: LogLevel, message: string) => {
  console.log(`Level: ${level}, Message: ${message}`);
}

function createLogger() {
  const logger: Partial<Logger> = {};

  for (let key of allLogLevels) {
    logger[key] = (message: string) => log(key, message);
  }

  return logger as Logger;
}

// runtime
const logger = createLogger();

logger.error('test error.');
logger.warning('test warning.');
logger.info('test info.');

TypeScript Playground 示例在这里


推荐阅读