Beginner's TypeScript Tutorial (18 exercises)
solution

Add Types to Object Params

There are multiple solutions to this problem.

Solution 1: Pass an Object Type Directly

Perhaps the simplest solution is to pass an object type directly to the params argument.

Use curly braces to represent the object, then create type inline:

export const addTwoNumbers = (params: { first: number; second: number }) => {
    ...

Note that TypeScript will understand if you use a comma between the first and second types like this:

params: {first: number, second: number}

However, Prettier will correct it to use semicolons instead.

Solution 2: Create a Named Type

A useful technique is creating a named type. Use the type keyword, then provide a name and object similar to the previous solution.

In this case, we'll name the type AddTowNumbersArgs and type first and second as number:

type AddTwoNumbersArgs = {
  first: number;
  second: number;
};

Now we can set the params to be typed as AddTowNumbersArgs:

export const addTwoNumbers = (params: AddTwoNumbersArgs) => {
  return params.first + params.second;
};

Solution 3: Create an Interface

Interfaces can be used to represent objects (they can do other things, but we're only concerned with objects for now).

Using interface is similar to using type.

interface AddTwoNumbersArgs {
  first: number;
  second: number;
};

export const addTwoNumbers = (params: AddTwoNumbersArgs) => {
  return params.first + params.second;
};

Choosing Inline vs. Type vs. Interface

The inline technique used in the first solution will provide a verbose error that includes the full object type:

Argument of type 'number' is not assignable to a parameter of type'{first: number; second: number;}'

But generally speaking, you should be using aliases instead of going inline.

So when should you choose type and when should you choose interface?

It comes down to the syntax you prefer.

Technically, type can represent anything. It could be a number, or a string, or a boolean.

TypeScript will give you an error if you try to use a string with interface:

// this won't work!

interface AddTwoNumbersArgs = string

When you're just getting started, it doesn't really matter if you choose type or interface.

Just be consistent!

Transcript

There are multiple solutions to this problem. The first one, and maybe one of the simplest to understand, is you can parse in an object type here direct to the params argument. Use these curly braces to represent and object, and then you create the type in line there.

You notice that TypeScript will understand if you use a comma in this situation, but you mostly, and Prettier will correct it, so you use semicolons, instead.

This is the first solution. The second solution is by creating a type here. We create a named type, give a type a name, which is pretty useful. We create it with this equals sign here. We say...basically parse the same thing as we had before, just inside a type there.

If I wanted to convert this to a type, I'll just create a new type here and say NewType and say type NewType = and just paste in what I copied there.

The third solution is to use an interface. An interface is pretty similar to type, but interfaces can only be used to represent objects and a couple of other things, but mostly objects in this basic course.

You may be wondering why would you choose type over interface? Type can technically represent anything. Type could be a number. It can be a string. It can be boolean. It can be absolutely anything, whereas an interface, if you try to say interface = string, it's going to yell at you. It's not going to let you. It's not very fun.

Why would you use interface over type? There used to be a lot of confusion over this. It's a question I get asked a lot.

To be honest, whatever syntax you prefer, you should choose and just stay consistent. Either one is going to give you...

You'll notice, too, if you...In this first solution, if I refactor this back to how it was, I'm actually going to get a more verbose error message if I do this rather than the other way. If I mess this up, and if I say...Let's say I remove one of these and we just add in a random number instead.

Then, it's going to say "Argument of type 'number' is not assignable to parameter of type..." and it gives it the literal value here, so it's spelled out.

Whereas if I do it on this one, where it has a type alias assigned to it and I go blah, blah, blah, blah, blah, blah, then it's going to say, "Argument of type 'number' is not assignable to type 'AddTwoNumbers Args'", which is better and a bit more readable, a bit more understandable.

In general, you should be extracting these out into their own aliases, but it doesn't really matter whether you use type or interface, especially when you're first starting out.