我之前在第一个循环中遇到了问题,因为迭代键的问题,现在用下面的代码解决了这个问题.PopupPopsDefined和PopupProps两种类型是相同的,除了PopupProps允许undefined.这就解决了我遇到的其他元素无法接受的键的问题.这里的代码都正确运行,我只是想更好地完成最后一部分,而不需要case语句和硬编码赋值.

mergeTool(baseConfig: PopupPropsDefined, overrides: PopupProps): PopupPropsDefined {
    const keys = Object.keys(overrides) as (keyof PopupProps)[];
    keys.forEach((key) => {
      const newValue = overrides[key];
      if (typeof newValue !== 'undefined') {
        this.setPropValue(key, baseConfig, newValue);
      }
    });
    return baseConfig;
  }

这些类型定义为:

export interface PopupProps {
  arrowDistance?: number;
  arrowHeight?: number;
  arrowOffset?: number;
  arrowWidth?: number;
  cornerRadius?: number;
  paddingX?: number;
  paddingY?: number;
  shiftX?: number;
  shiftY?: number;
  zIndex?: number;
  isManual?: boolean;
  isModal?: boolean;
  isTooltip?: boolean;
  logging?: boolean;
  debugMode?: boolean;
  direction?: PopupDirection;
  eventOff?: keyof HTMLElementEventMap;
  eventOn?: keyof HTMLElementEventMap;
  positioner?: string;
}

export interface PopupPropsDefined {
  arrowDistance: number;
  arrowHeight: number;
  arrowOffset: number;
  arrowWidth: number;
  cornerRadius: number;
  paddingX: number;
  paddingY: number;
  shiftX: number;
  shiftY: number;
  zIndex: number;
  isManual: boolean;
  isModal: boolean;
  isTooltip: boolean;
  logging: boolean;
  debugMode: boolean;
  direction: PopupDirection;
  eventOff: keyof HTMLElementEventMap;
  eventOn: keyof HTMLElementEventMap;
  positioner: string;
}

下面是我想用更好的方式来做的丑陋代码.有没有什么方法可以检测我复制值的对象的类型,这样我就不必像这样有switch语句了.部分原因是它是如此的不可维护,如果我添加一个新属性,我必须记住将其添加到这里.

  setPropValue(key: string, config: PopupPropsDefined, value: number | boolean | string) {
    switch (key) {
      case 'arrowDistance':
      case 'arrowHeight':
      case 'arrowOffset':
      case 'arrowWidth':
      case 'cornerRadius':
      case 'paddingX':
      case 'paddingY':
      case 'shiftX':
      case 'shiftY':
      case 'zIndex':
        config[key] = <number>value;
        break;
      case 'isModal':
      case 'isTooltip':
      case 'logging':
      case 'debugMode':
      case 'isManual':
        config[key] = <boolean>value;
        break;
      case 'direction':
        config.direction = value as PopupDirection;
        break;
      case 'eventOff':
      case 'eventOn':
        config[key] = value as keyof HTMLElementEventMap;
        break;
      case 'positioner':
        config.positioner = <string>value;
        break;
    }
  }

推荐答案

setPropValue()版本的问题是不能保证keyvalue彼此有任何关系;key可以是任何字符串,value可以是任何number | boolean | string.这意味着你可以调用setPropValue("oopsiePoopsie", 123)setPropValue("arrowDistance", "whoopsieDoodle"),编译器会允许这样做,这迫使你在函数内部进行各种判断,并试图避免和 suppress 错误.

假设在运行时setPropValue()中的所有代码都只是执行config[key] = value,我们应该寻找一个只包含这一行的解决方案. 这样做的方法是在K中生成setPropValue() generickey的类型,应该是constrainedPopupPropsDefined的键,然后value的类型应该是当你用K的键index into一个PopupPropsDefined时得到的属性的类型.

像这样:

setPropValue<K extends keyof PopupPropsDefined>(
    key: K,
    config: PopupPropsDefined,
    value: PopupPropsDefined[K]
) {
    config[key] = value; // okay
}

因为赋值config[key] = value在两侧都有索引访问类型PopupPropsDefined[K],所以编译时不会出错. 类型value被声明为该类型,而类型config[key]被声明为该类型,因为您使用类型K的键索引到PopupPropsDefined.

现在,它的行为也如调用者的预期一样:

x.setPropValue("arrowDistance", config, 1); // okay
x.setPropValue("oopsiePoopsie", config, 123); // error!
// ----------> ~~~~~~~~~~~~~~~
// Argument of type '"oopsiePoopsie"' is not assignable 
// to parameter of type 'keyof PopupPropsDefined'.
x.setPropValue("arrowDistance", config, "whoopsieDoodle");
// -----------------------------------> ~~~~~~~~~~~~~~~~
// Argument of type 'string' is not assignable 
// to parameter of type 'number'.

Playground link to code

Typescript相关问答推荐

如何根据模板类型实现不同的模板函数行为?

状态更新后未触发特定元素的Reaction CSS转换

如何编写一个类型脚本函数,将一个对象映射(转换)为另一个对象并推断返回类型?

在包含泛型的类型脚本中引用递归类型A<;-&B

类型脚本满足将布尔类型转换为文字.这正常吗?

使用KeyOf和Never的循环引用

如何 bootstrap TS编译器为类型化属性`T`推断正确的类型?

@TANSTACK/REACT-QUERY中发生Mutations 后的数据刷新问题

在Cypress中,是否可以在不标识错误的情况下对元素调用.Click()方法?

当传递带有或不带有参数的函数作为组件props 时,我应该如何指定类型?

字符串文字联合的分布式条件类型

有没有办法在Reaction组件中动态导入打字脚本`type`?

如何在Type脚本中创建一个只接受两个对象之间具有相同值类型的键的接口?

TS不能自己推断函数返回类型

为什么`map()`返回类型不能维护与输入相同数量的值?

可以用任意类型实例化,该类型可能与

如何通过nx找到所有受影响的项目?

带有过滤键的 Typescript 映射类型

Typescript 子类继承的方法允许参数中未定义的键

基于泛型的柯里化函数的条件参数