Reputation: 11518
With a very simple and readable function like:
function signIn(...) {...}
To define its type with an existing definition Action
, it becomes something that's not very readable:
const signIn: Action = function (...) {...}
That is a lot of changes, and not very readable, just to specify that the function is of the Action
type.
I wonder if there's any way to not use the const
and to keep signIn
next to function
? I realise I can copy the existing type definition Action
and apply it directly to the function, but it's not good for maintainability – what if the original Action
definition changes?
Upvotes: 0
Views: 85
Reputation: 329228
So you have a function type like this:
type MyFunc = (x: string, y: number) => boolean;
but which can't be used as an annotation for a general function declaration:
// where to annotate?
function myFunc(x: string, y: number) {
return x.length > y;
}
It would be nice if you could annotate the function above somehow, like the following hypothetical syntax (which currently doesn't work):
// do not do this, it doesn't work:
function myFunc: MyFunc (x, y) {
return x.length > y;
}
Sadly this is not currently supported in TypeScript. There is, however, an open suggestion for this feature: microsoft/TypeScript#22063. It doesn't look like there's been any movement on that issue, but if you head over there and give it a 👍 you might very slightly increase the chance of it being implemented. Or, if your use case is particularly compelling and not already mentioned, you might make a comment there describing it. Realistically this might never make it into the language.
So what are the workarounds? The obvious one and the best one is to change your declared function into a declared const
of a function type, as you've already done:
const myFunc: MyFunc = function (x, y) {
return x.length > y;
}
You could opt to use the built-in utility types Parameters<T>
and ReturnType<T>
to convert the annotation of the function itself into annotation of the arguments and return type, but it's so hideous that I can't imagine anyone would prefer this to the previous version:
function myFunc(...[x, y]: Parameters<MyFunc>): ReturnType<MyFunc> {
return x.length > y;
}
Another possibility is to try using the type system to verify that your declared function is assignable to the MyFunc
type in a separate line. If you have a helper type called Extends
:
type Extends<T, U extends T> = void;
then you can do this:
type MyFuncWorks = Extends<MyFunc, typeof myFunc>; // okay
function myFunc(x: string, y: number) {
return x.length > y;
}
and you'd see an error if you changed myFunc
to something incompatible:
type MyFuncBroken = Extends<MyFunc, typeof myFunc>; // error!
// number is not boolean ---------> ~~~~~~~~~~~~~
function myFunc(x: string, y: number) {
return x.length + y; // + instead of <, oops
}
The least ugly workaround is still the function-typed const
, so if I were you, I'd go with that.
Okay, hope that helps; good luck!
Upvotes: 3