10

Rather than calling functions where the arguments are passed individually, I prefer to pass them as an object so that the order is not important.

For example,

const sum = ({ arg1, arg2, arg3 }) => arg1 + arg2 + arg3;

Now I'm migrating some code that I have across, to Typescript and I am unsure how I am supposed to define the interface for such a function.

I've tried something like this and it doesn't work:

Enter image description here

Any clues?

4 Answers 4

9

Use:

interface InputObj {
    arg1: number;
    arg2: number;
    arg3: number;
}

interface ExampleProps {
    sum: (input: InputObj) => number
}

Or inline:

interface ExampleProps {
  sum: (
    input: {
      arg1: number;
      arg2: number;
      arg3: number;
    }
  ) => number;
}

But depending on your use case you may not need to define ExampleProps. Here is your sum function without the arbitrary input object name:

const sum = ({
  arg1,
  arg2,
  arg3
}: {
  arg1: number;
  arg2: number;
  arg3: number;
}) => arg1 + arg2 + arg3;
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @XDgg. Yes, I think that would work, but given that just about everytime I define a function I wrap the arguments up as a single object it will be cumbersome to do define a separate interface for every function. Surely there's a way to define that inline in one interface file?
Functions are not annotated with interface in typescript. You cannot apply ExampleProps to sum. Poor design.
4

Here is a fully annotated example as function expression:

const sum: ({ 
  arg1, 
  arg2,
  arg3 
}: {
  arg1: number;
  arg2: number;
  arg3: number;
}) => number = ({ arg1, arg2, arg3 }) => arg1 + arg2 + arg3;

Here is another and better alternative for arrow functions. Only arguments are annotated and compiler can infer return type correctly. Function has less clutter and works just as before.

const sum = ({ 
  arg1,
  arg2,
  arg3
}: {
  arg1: number;
  arg2: number;
  arg3: number;
}) => arg1 + arg2 + arg3;

If you are going to annotate your function in a seperate file:

interface Args {
  arg1: number;
  arg2: number;
  arg3: number;
}

type Sum = (input: Args) => number;
const sum: Sum = ({ arg1, arg2, arg3 }) => arg1 + arg2 + arg3;

You can use any as argument type if argument types are not known. Return type will be inferred as any:

const sum = ({ 
  arg1,
  arg2,
  arg3
}: any) => arg1 + arg2 + arg3;

So this one is equivalent to previous example:

const sum: ({ arg1, arg2, arg3 }: any) => any

This may not make that much sense for arrow functions but you can set types for known arguments and use key-value pairs for annotating addititional argumens:

const sum = ({ 
  arg1,
  arg2,
  arg3
}: {
  arg1: number;
  arg2: number;
  arg3: number;
  [key: string]: number;
}) => arg1 + arg2 + arg3;

You can also use generics:

interface Args {
  arg1: number;
  arg2: number;
  arg3: number;
}

const sum = <T extends Args>({ 
  arg1,
  arg2,
  arg3
}: T) => arg1 + arg2 + arg3;

Here is same examples, sum as function statement.

function sum({
  arg1,
  arg2,
  arg3
}: {
  arg1: number;
  arg2: number;
  arg3: number;
}): number {
  return arg1 + arg2 + arg3;
}

If you have complicated implementation detail in your function's body, function statement can be better choice for its ergonomics. Plus generics looks less clumsy on function statements.

Comments

4

If you need to explicitly annotate a function type you can go with:

type Foo = (object: { arg1: number, arg2: number; arg3: number }) => number;

const bar: Foo = ({arg1, arg2, arg3}) =>  arg1 + arg2 + arg3 

To play around with type annotations and share results I advise TypeScript Playground <= check there above :)

Comments

-4

I have not tried TypeScript. In JavaScript, I would also consider including default values for the properties of the object to avoid the error

Uncaught TypeError: Cannot destructure property arg1 of 'undefined' or 'null'.

for

sum()

const sum = ({ arg1, arg2, arg3 }) =>
  arg1 + arg2 + arg3;

try {
  console.log(sum())
} catch (e) {
  console.error(e)
}

which can be avoided by setting each value to 0 where the expected parameters and return value is a JavaScript integer

const sum = ({ arg1 = 0, arg2 = 0, arg3 = 0 } = {}) =>
  arg1 + arg2 + arg3;

try {
  console.log(sum()) // 0
} catch (e) {
  console.error(e)
}

1 Comment

Thanks for the advice but it doesn't answer my specific question.

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.