0

I am learning Typescript and I read two ways to write the function type : with a fat arrow or with an object literal.

For example :

let myAdd1: (x: number, y: number) => number =
    function(x: number, y: number): number {return x + y; };

let myAdd2: { (x: number, y: number): number } =
    function(x: number, y: number): number {return x + y; };

What are the reasons to use one rather the other ?

Thanks for answer.

0

2 Answers 2

1

Those are identical types written in different ways:

let myAdd1: (x: number, y: number) => number;
type Func = typeof myAdd1;
// type Func = (x: number, y: number) => number
let myAdd2: { (x: number, y: number): number };
type Callable = typeof myAdd2;
// type Callable = (x: number, y: number) => number

You can see that the compiler considers both Func and Callable to be of type (x: number, y: number) => number. Since they're the same, reasons for preferring one to the other are probably subjective and opinion-based.


However, if you start adding properties to the function then the object notation is probably preferable as easier to represent:

let func1: ((x: string) => string) & { color: string } =
  Object.assign((z: string) => z.toUpperCase(), { color: "red" });
type FuncWithProp = typeof func1;
// type FuncWithProp = ((x: string) => string) & { color: string; }
let func2: { (x: string): string; color: string } = 
  Object.assign((z: string) => z.toLowerCase(), { color: "green" });
type CallableWithProp = typeof func2;
// type CallableWithProp = { (x: string): string; color: string }

The types FuncWithProp and CallableWithProp are no longer considered to be identical, but they are mutually assignable (meaning the compiler sees that each extends the other):

type MutuallyExtends<T extends U, U extends V, V = T> = void;
type FuncVsCallableWithprops = MutuallyExtends<FuncWithProp, CallableWithProp>; // okay

So again you can probably use either one in principle, but the FuncWithProp is an intersection type whereas CallableWithProp is a single object type which might behave better in certain edge cases.


Okay, hope that helps; good luck!

Link to code

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. It helps me.
1

The first example is a normal typed function declaration and assignment. The second example uses function overloads shorthand.

Consider we have some normal function overloads:

function myMultiAdd(x: number, y: number): number;
function myMultiAdd(x: number, y: number, z?: number): number {
    return x + y + (z ? z : 0);
}

Both myMultiAdd(1, 2) and myMultiAdd(1, 2, 3) will work. It's inconvenient to use this pattern when having many function overloads because we will repeat the same name again and again, thus typescript has a short function overloads syntax like this:

let myMultiAdd: {
    (x: number, y: number): number,
    (x: number, y: number, z: number): number
} = function (x: number, y: number, z?: number): number {
    return x + y + (z ? z : 0);
}

So, if you don't want to use function overloads, then you should always use the first example to type functions.

1 Comment

Thanks a lot. I am sorry I could not accept TWO answers. However, your answer is very interesting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.