【问题标题】:TypeScript interface that allows other properties允许其他属性的 TypeScript 接口
【发布时间】:2016-02-23 12:43:50
【问题描述】:

总而言之,是否可以有一个接口声明一些基本属性,但不限制附加属性?这是我目前的情况:

我正在使用Flux pattern,它定义了一个通用调度程序:

class Dispatcher<TPayload> {
    dispatch(arg:TPayload):void { }
}

然后我使用自己的有效负载类型创建一个调度程序,如下所示:

interface ActionPayload {
    actionType: string
}

const dispatcher = new Dispatcher<ActionPayload>();

现在我有一些动作代码应该发送带有一些附加数据的有效负载,但ActionPayload 接口只允许actionType。换句话说,这段代码:

interface SomePayload extends ActionPayload {
    someOtherData: any
}

class SomeActions {
    doSomething():void {
        dispatcher.dispatch({
            actionType: "hello",
            someOtherData: {}
        })
    }
}

给出一个编译错误,因为someOtherDataActionPayload 接口不匹配。问题是许多不同的“动作”类将重用同一个调度程序,所以虽然这里是someOtherData,但那里可能是anotherKindOfData,等等。目前,我所能做的就是使用new Dispatcher&lt;any&gt;(),因为将调度不同的操作。不过,所有操作都共享一个基础ActionPayload,所以我希望能够限制new Dispatcher&lt;extends ActionPayload&gt;() 之类的类型。这样的事情可能吗?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    我想我找到了我要找的东西。我可以将调度的对象强制转换为SomePayload,TSC 会验证它是否与强制转换接口和调度程序的TPayload 兼容:

        dispatcher.dispatch(<SomePayload>{
            actionType: "hello",
            someOtherData: {}
        })
    

    Example online.

    【讨论】:

      【解决方案2】:

      如果您希望ActionPayload 接受任何其他属性,您可以添加索引器:

      interface ActionPayload {
          actionType: string;
      
          // Keys can be strings, numbers, or symbols.
          // If you know it to be strings only, you can also restrict it to that.
          // For the value you can use any or unknown, 
          // with unknown being the more defensive approach.
          [x: string | number | symbol]: unknown;
      }
      

      https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#strict-object-literal-assignment-checking

      【讨论】:

      • 谢谢,这是很好的信息。它准确地回答了我过度简化的标题......事实证明,有一种方法可以通过简单地转换对象文字来在我的问题的细节中使用扩展的&lt;SomePayload&gt;。很抱歉这个笨拙的问题。我应该尝试修复标题和摘要,例如“如何实现子接口并满足具有对象文字的超级接口”,还是只接受您的答案?
      • 一个或另一个对我来说很好。更改标题可能更好地反映问题。
      • 遗憾的是,如果我们添加其他类型的字段,例如拥有一个 Date 属性和动态字符串属性,这将不起作用
      • type: unknown 会比 any 好。
      【解决方案3】:
      interface Options {
        darkMode?: boolean;
        [otherOptions: string]: unknown;
        }
      

      【讨论】:

        【解决方案4】:

        如果你的类型是从对象定义中推断出来的,你可以将类型断言为原始类型的union{[key: string]: any]}

        const obj = { foo: 42 };
        return obj as typeof obj & {[key: string]: any]};
        

        这样,IntelliSense 会建议您foo,但不会在您尝试分配或检索另一个密钥时抱怨。

        无论如何,如果额外的键很少并且它们是先验已知的,您可以在类型定义中将它们作为可选添加:

        const obj: {foo: number; bar?: string} = {foo: 42}
        

        【讨论】:

        • 这也可以拼写为typeof obj & Record
        【解决方案5】:

        我通过创建类似的东西解决了这个问题

        type Make "Volvo" | "Polestar" | "Saab";
        interface BaseCar {
            make: Make;
            horsePower: number;
            allWheelDrive: boolean;
        }
        type Car = BaseCar & Record<string, string>;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-07-16
          • 1970-01-01
          • 1970-01-01
          • 2021-10-14
          • 2023-04-08
          • 2018-11-30
          • 2015-05-13
          相关资源
          最近更新 更多