How to merge several object methods declared using generics in TypeScript?
THE SCOPE:
Here is what I love about TypeScript:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
emit(type: 'stop', payload: { pid: number }) : bool;
}
… and then, while I'm writing this commandBus.emit('stop',
IntelliSense will tell me that the next function argument is payload: { pid: number }
. This is priceless!
It is also possible to split it into several interfaces and TypeScript will merge it and the result will be the same:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
}
interface CommandBus {
emit(type: 'stop', payload: { pid: number }) : bool;
}
This is what I use for my application. In different packages, I extend an interface with methods specific to that package. But the method signature is more complicated than the one above, and it has more common things, so I've created the generic:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
And I've tried to use it with my interface:
interface CommandBus {
emit: IEmit<'execute', { command: string }>;
emit: IEmit<'stop', { pid: number }>;
}
THE PROBLEM: TypeScript cannot handle this syntax, it only applies the first emit
declaration and ignoring others.
THE QUESTION: How do I manage to overload a method in an interface using function types or interfaces?
typescript
add a comment |
THE SCOPE:
Here is what I love about TypeScript:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
emit(type: 'stop', payload: { pid: number }) : bool;
}
… and then, while I'm writing this commandBus.emit('stop',
IntelliSense will tell me that the next function argument is payload: { pid: number }
. This is priceless!
It is also possible to split it into several interfaces and TypeScript will merge it and the result will be the same:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
}
interface CommandBus {
emit(type: 'stop', payload: { pid: number }) : bool;
}
This is what I use for my application. In different packages, I extend an interface with methods specific to that package. But the method signature is more complicated than the one above, and it has more common things, so I've created the generic:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
And I've tried to use it with my interface:
interface CommandBus {
emit: IEmit<'execute', { command: string }>;
emit: IEmit<'stop', { pid: number }>;
}
THE PROBLEM: TypeScript cannot handle this syntax, it only applies the first emit
declaration and ignoring others.
THE QUESTION: How do I manage to overload a method in an interface using function types or interfaces?
typescript
add a comment |
THE SCOPE:
Here is what I love about TypeScript:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
emit(type: 'stop', payload: { pid: number }) : bool;
}
… and then, while I'm writing this commandBus.emit('stop',
IntelliSense will tell me that the next function argument is payload: { pid: number }
. This is priceless!
It is also possible to split it into several interfaces and TypeScript will merge it and the result will be the same:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
}
interface CommandBus {
emit(type: 'stop', payload: { pid: number }) : bool;
}
This is what I use for my application. In different packages, I extend an interface with methods specific to that package. But the method signature is more complicated than the one above, and it has more common things, so I've created the generic:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
And I've tried to use it with my interface:
interface CommandBus {
emit: IEmit<'execute', { command: string }>;
emit: IEmit<'stop', { pid: number }>;
}
THE PROBLEM: TypeScript cannot handle this syntax, it only applies the first emit
declaration and ignoring others.
THE QUESTION: How do I manage to overload a method in an interface using function types or interfaces?
typescript
THE SCOPE:
Here is what I love about TypeScript:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
emit(type: 'stop', payload: { pid: number }) : bool;
}
… and then, while I'm writing this commandBus.emit('stop',
IntelliSense will tell me that the next function argument is payload: { pid: number }
. This is priceless!
It is also possible to split it into several interfaces and TypeScript will merge it and the result will be the same:
interface CommandBus {
emit(type: 'execute', payload: { command: string }) : number;
}
interface CommandBus {
emit(type: 'stop', payload: { pid: number }) : bool;
}
This is what I use for my application. In different packages, I extend an interface with methods specific to that package. But the method signature is more complicated than the one above, and it has more common things, so I've created the generic:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
And I've tried to use it with my interface:
interface CommandBus {
emit: IEmit<'execute', { command: string }>;
emit: IEmit<'stop', { pid: number }>;
}
THE PROBLEM: TypeScript cannot handle this syntax, it only applies the first emit
declaration and ignoring others.
THE QUESTION: How do I manage to overload a method in an interface using function types or interfaces?
typescript
typescript
asked Nov 21 '18 at 11:56
termosatermosa
1367
1367
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Declaration merging can't change the type of an existing field (this is a design limitation). An alternate solution would be to declare a type for the emit
field and extend that:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
interface CommandBus {
emit: CommandBusEmit;
}
//default type for the emit field
interface CommandBusEmit { }
//extensions to it
interface CommandBusEmit extends IEmit<'execute', { command: string }> { }
interface CommandBusEmit extends IEmit<'stop', { pid: number }> { }
declare let cb: CommandBus;
cb.emit('execute', "", { payload : { command: ""}})
cb.emit('stop', "", { payload: { command: "" } }) // error
cb.emit('stop', "", { payload : { pid: 1}}) // ok
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53411529%2fhow-to-merge-several-object-methods-declared-using-generics-in-typescript%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Declaration merging can't change the type of an existing field (this is a design limitation). An alternate solution would be to declare a type for the emit
field and extend that:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
interface CommandBus {
emit: CommandBusEmit;
}
//default type for the emit field
interface CommandBusEmit { }
//extensions to it
interface CommandBusEmit extends IEmit<'execute', { command: string }> { }
interface CommandBusEmit extends IEmit<'stop', { pid: number }> { }
declare let cb: CommandBus;
cb.emit('execute', "", { payload : { command: ""}})
cb.emit('stop', "", { payload: { command: "" } }) // error
cb.emit('stop', "", { payload : { pid: 1}}) // ok
add a comment |
Declaration merging can't change the type of an existing field (this is a design limitation). An alternate solution would be to declare a type for the emit
field and extend that:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
interface CommandBus {
emit: CommandBusEmit;
}
//default type for the emit field
interface CommandBusEmit { }
//extensions to it
interface CommandBusEmit extends IEmit<'execute', { command: string }> { }
interface CommandBusEmit extends IEmit<'stop', { pid: number }> { }
declare let cb: CommandBus;
cb.emit('execute', "", { payload : { command: ""}})
cb.emit('stop', "", { payload: { command: "" } }) // error
cb.emit('stop', "", { payload : { pid: 1}}) // ok
add a comment |
Declaration merging can't change the type of an existing field (this is a design limitation). An alternate solution would be to declare a type for the emit
field and extend that:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
interface CommandBus {
emit: CommandBusEmit;
}
//default type for the emit field
interface CommandBusEmit { }
//extensions to it
interface CommandBusEmit extends IEmit<'execute', { command: string }> { }
interface CommandBusEmit extends IEmit<'stop', { pid: number }> { }
declare let cb: CommandBus;
cb.emit('execute', "", { payload : { command: ""}})
cb.emit('stop', "", { payload: { command: "" } }) // error
cb.emit('stop', "", { payload : { pid: 1}}) // ok
Declaration merging can't change the type of an existing field (this is a design limitation). An alternate solution would be to declare a type for the emit
field and extend that:
interface IEmit<TType, TPayload> {
(type: TType, id: string, options: { payload: TPayload }) : void
}
interface CommandBus {
emit: CommandBusEmit;
}
//default type for the emit field
interface CommandBusEmit { }
//extensions to it
interface CommandBusEmit extends IEmit<'execute', { command: string }> { }
interface CommandBusEmit extends IEmit<'stop', { pid: number }> { }
declare let cb: CommandBus;
cb.emit('execute', "", { payload : { command: ""}})
cb.emit('stop', "", { payload: { command: "" } }) // error
cb.emit('stop', "", { payload : { pid: 1}}) // ok
answered Nov 21 '18 at 12:08
Titian Cernicova-DragomirTitian Cernicova-Dragomir
69.3k34765
69.3k34765
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53411529%2fhow-to-merge-several-object-methods-declared-using-generics-in-typescript%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown