Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript interface that allows other properties

Tags:

typescript

In summary, is it possible to have an interface that declares some base properties, but does not restrict additional properties? This is my current situation:

I'm using the Flux pattern, which defines a generic dispatcher:

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

I then create a dispatcher with my own payload type, like this:

interface ActionPayload {
    actionType: string
}

const dispatcher = new Dispatcher<ActionPayload>();

Now I have some action code that should dispatch a payload with some additional data, but the ActionPayload interface only allows for actionType. In other words, this code:

interface SomePayload extends ActionPayload {
    someOtherData: any
}

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

Gives a compile-error because someOtherData does not match the ActionPayload interface. The issue is that many different "action" classes will re-use the same dispatcher, so while it's someOtherData here it might be anotherKindOfData over there, and so on. At the moment, all I can do to accomodate this is use new Dispatcher<any>() because different actions will be dispatched. All actions share a base ActionPayload, though, so I was hoping to be able to constrain the type like new Dispatcher<extends ActionPayload>() or something. Is something like that possible?

like image 896
Aaron Beall Avatar asked Nov 20 '15 21:11

Aaron Beall


People also ask

Can we have an interface with default properties in TypeScript?

To set default values for an interface in TypeScript, create an initializer function, which defines the default values for the type and use the spread syntax (...) to override the defaults with user-provided values.

How do you override properties in interface TypeScript?

Use the Omit utility type to override the type of an interface property, e.g. interface SpecificLocation extends Omit<Location, 'address'> {address: newType} . The Omit utility type constructs a new type by removing the specified keys from the existing type.

CAN interfaces extend other interfaces TypeScript?

An interface can be extended by other interfaces. In other words, an interface can inherit from other interface. Typescript allows an interface to inherit from multiple interfaces. Use the extends keyword to implement inheritance among interfaces.

Can TypeScript interface have functions?

TypeScript Interface can be used to define a function type by ensuring a function signature. We use the optional property using a question mark before the property name colon. This optional property indicates that objects belonging to the Interface may or may not have to define these properties.


3 Answers

If you want ActionPayload to accept any other property you can add an indexer:

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;
}

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

like image 146
Sebastien Avatar answered Oct 19 '22 23:10

Sebastien


interface Options {
  darkMode?: boolean;
  [otherOptions: string]: unknown;
  }
like image 6
zloctb Avatar answered Oct 19 '22 23:10

zloctb


I solved this by creating something like

type Make = "Volvo" | "Polestar" | "Saab";
interface BaseCar {
    make: Make;
    horsePower: number;
    allWheelDrive: boolean;
}
type Car = BaseCar & Record<string, string|number|boolean>;
like image 3
brendangibson Avatar answered Oct 19 '22 23:10

brendangibson