0

I have this type:

type EventCallback<T> = (ev: T, anotherParam: string, lastParam: string) => void;

And this interface:

interface CustomEvent {
    ...
    payload: any;
}

And this arbitrary class:

class ArbitraryClass {
    methodOnArbitraryClass() {
        // do stuff
    }
}

I then create functions of this shape:

const exampleCallback: EventCallback<CustomEvent> = (ev: { payload: CustomEvent }, anotherParam: "foo", lastParam: "bar") => {
    // handle event
};

All good.

Now I want to add a parameter to callbacks of this shape, without changing the return type, and while still using the EventCallback<CustomEvent>, say we call this type DesiredCallback, such that:

const newExampleCallback: DesiredCallback = (newParam: ArbitraryClass, ev: { payload: CustomEvent }, anotherParam: "foo", lastParam: "bar) => {
    // handle event
};

I am looking for a way to define the DesiredCallback type by extending the EventCallback type, which means only defining the new parameter(s), and leaving the parent EventCallback type responsible for defining the other parameters, which the DesiredCallback type inherits.

I would be fine with the newParam parameter being ordered anywhere in the positional parameter list (beginning or end).

zr0gravity7
  • 2,917
  • 1
  • 12
  • 33
  • 2
    `type ExtendedEventCallback = (newParam:String, ev: T) => void;` – Lesiak Jun 29 '20 at 23:15
  • For context, in [this](https://stackoverflow.com/questions/62603218/specify-type-of-this-at-callback-creation) post I figured out how to declare type for `this` in a function using TypeSript's fake `this` param. Now I want to pivot away from the approach, and instead of expecting `this` to be bound to the desired object by the callback client (using `exampleCallback.bind(desiredObj)` for example), I want to explicitly specify the desired object as a param (like `newExampleCallback.bind(undefined, desiredObj))` – zr0gravity7 Jun 29 '20 at 23:19
  • @Lesiak Is there a way to do this inline, i.e. without aliasing another type name? – zr0gravity7 Jun 29 '20 at 23:21
  • 2
    Can you put all necessary context in this question? Lesiak's comment looks like the right answer to me; if it's not, please elaborate in the question itself. Do you want to do it programmatically like [this](https://www.typescriptlang.org/play/#code/C4TwDgpgBAogbhAdsAwgQwDYYEZoMYDWAPACoB8UAvFABQRwBcUJAlFRXAPYCWAJgNwAoPBjQBnMVACCAJ2zdgMtDJApREqAG8oAWwjAAFp14B5RLPmLlq9WJpttAXyiPBoSFAAKMiJES9PZTQdUgAaKAAxKAgAD2AkXkkaADpU5QBzMSY0RBA2SgockApqKNj4-yTU5IysqG5EADMIGWl8igbm1oAlKAB+WmAmEnDq2qYpdqhuoTdwaAARCDFuH150LFxCUhKvHz8AoJCLBSUVNXExcPgkVEwcfGJyMn4gA)? Or something else? – jcalz Jun 29 '20 at 23:58
  • Edited the question. Lesiak's answer is good, I just don't want to alias another type as an intermediary step, I just want to create and set the type on the variable directly. And nothing to do with creating the type dynamically. Basically I want to use Lesiak's answer, without having to create another type alias. – zr0gravity7 Jun 30 '20 at 00:04
  • 1
    So then use it! `const newExampleCallback: (newParam: ArbitraryClass, ev: CustomEvent) => void = ...`. But why do you even need to annotate the type? What breaks if you just write `const newExampleCallback = (newParam: ArbitraryClass, ev: { payload: CustomEvent }) => { /* impl */ };` without a type annotation? – jcalz Jun 30 '20 at 00:09
  • @jcalz but this answer does not actually satisfy my problem. A stated in the title, I wish to extend a function type, not redefine that type using the same building blocks, which is what the above solutions are offering. For example, if the type `EventCallback` had numerous positional parameters, neither of the offered solutions would be appropriate, because I would be repeating the defined type in the new type, rather than simply extending it. – zr0gravity7 Jul 24 '20 at 20:56
  • That was a long delay between comments. I do not understand in what sense you mean "extend" here. Can you write up a sketch of what kind of thing you expect an acceptable answer to look like? I would think `const newExampleCallback: SomeFunctionOf> = ...` with a suitably defined `SomeFunctionOf` would be what you want, but I guess not? You don't want to have to define `SomeFunctionOf`? – jcalz Jul 25 '20 at 01:38
  • Thank you for your continued help. I revised the question to focus the desired goal, with a clearer definition for the expected result. – zr0gravity7 Jul 25 '20 at 06:52
  • 2
    Function prototypes/definitions cannot easily be extended like classes can because function parameters have positional significance. Extending a function prototype requires you to specify the position of your new argument along with the current arguments (is it at the beginning, the 2nd place, the end?) and happily the syntax for this feature if it existed would look exactly like a defining new function prototype so it would be redundant from a function type definition. I would be interested though to know if you have experience of any language which has such a feature – slebetman Jul 25 '20 at 07:11
  • @zr0gravity7 I’m still not sure what you’re looking for and why previous suggestions are not sufficient. TypeScript does not have built-in syntax to add a parameter to an existing function type; it cannot be done with `extends`. Such an operation *can* be expressed via a type function, but the standard TS library does not already include such a definition as a [utility type](https://www.typescriptlang.org/docs/handbook/utility-types.html). You can define it yourself and then use it wherever you want, though. I gave a `PrependParam` definition that does this, but you don’t want to use it. – jcalz Jul 25 '20 at 11:48
  • Specifically, [this](https://www.typescriptlang.org/play/#code/C4TwDgpgBACgThSA7AJjAhndBbAPAFQBooAxKCAD2AlQGcoAKAOhcwHNaAuKdJEASigBeAHw8+YoaXJUaKes1ZwO3AJZIAZhDhQAgoNFR1WnQCUoAfkbBuRKCybsueg2PPckEAG7aA3EA) is what I’d expect the answer to use. – jcalz Jul 25 '20 at 11:52
  • Unfortunately I am not experienced enough at TS to be able to validate that solution, but in any case I will probably not end up using it as it adds more complexity than clarity to our codebase. If you post this comment as an answer I can accept it, since it is technically the answer, but I am also contempt with the answer that there is no trivial way of doing this that is better than just redefining a function prototype as @slebetman explained. – zr0gravity7 Jul 25 '20 at 17:41

0 Answers0