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?
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.
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.
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.
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.
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
interface Options {
darkMode?: boolean;
[otherOptions: string]: unknown;
}
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>;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With