Infer types from objects and arrays with typescript
Published: 2022-04-09 19:38:16

## Motivación

Sometimes when we are using  typescript we will need to use the object's keys or the object's values as a type, even some cases we need to use the values in an array as a type as well.
What I want with this post is to explain how to do it  in a easy way, and by publishing it I will always have a place to return to if I forget (no-kidding) 😂

## Objects

### Using typeof

When we use objects,  we might want to to make an interface or type to describe the types inside the object, this is fine, but for some cases where we also need to create an object based on this interface we might have some code that might look like duplicate, for example:

```typescript
interface Fruit {
  name: string;
  price: number;
  available: boolean;
}
const fruit: Fruit = {
  name: "Apple",
  price: 4,
  available: true
}
```

We could transform this to a few lines of code for some specific cases:

```typescript
const fruit = {
  name: "Apple",
  price: 4,
  available: true
}
type Fruit = typeof fruit;
```

A common case of this could be when using React we declare an initial state, for example:

```typescript
const initialState = {
  name: "Apple",
  price: 4,
  available: true
}

type Fruit = typeof initialState;

function FruitComponent() {
  const [fruit, setFruit] = useState(initialState);
  {...}
}
```

This way it's easy to then use the `Fruit` type as a parameter to any handler-function.

### Using keyof

Using the keyof typescript will generate a new type from the keys of the object. Let's use the following object as an example. Here is the [documentation](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html)

```typescript
const fruits = {
  "cod-1": 'Apple',
  "cod-2": 'Pear',
  "cod-3": 'Orange'
}
```

Suppose we have a function where we receive the code of the fruit but it must return the name of the fruit.

```typescript
function getFruitName(code: string) {
  const name = fruits[code];
  return name;
}
```

In this case using typescript we would have this error: `... type 'string' can't be used to index type { ... }` since `string` is not guaranteed to actually match the keys of the object in this case with `"code-1" | "code-2" | "code-3"` for this reason the code parameter should have a more exact type, we will do it using `keyof`

```typescript
type Code = keyof typeof fruits;
function getFruitName(code: Code) {
  const name = fruits[code];
  return name;
}
```

We were able to do this: `type Code = "code-1" | "code-2" | "code-3"`, but to be honest it would only work for small cases like this, it's not scalable.

### Indexed Access Type

This is one of my favorite features, in some cases we need the type of a single property on an object/interface/type so this features will help us. Documentation [here](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html)

Suppose we have the following object:

```typescript
const fruit = {
  name: "Apple",
  price: 4,
  available: true
}
```

What happens if we want to know the type of the property price then we can do something like this:

```typescript
// Price expects to be number
type Price = typeof fruit["price"]
```

By using the property in square brackets that we want the typescript to get it from, this also works for interface and type, we just have to omit the `typeof` here is the example for interface, it's same for objects as a type

```typescript
interface TFruit {
  name: string,
  price: number,
  available: boolean
};

// Available expects to be boolean
type Available = TFruit["available"];
```

There is an additional use case for `Indexed Access Type`, but we will explain it later.

### What about valueof?

An unusual but possible use case is that we need to use the values of an object as a type, buuut _**valueof doesn't exist**_, don't worry, we have a solution for this and it's quite simple.

The first step is to get the type of the object keys as we did before:

```typescript
const fruits = {
  "cod-1": 'Apple',
  "cod-2": 'Pear',
  "cod-3": 'Orange'
};

type Code = keyof typeof fruits;
```

Now we are going to use this type and combined with the Indexed Access Type we will get the values of the object as a type

```typescript
type FruitName = typeof fruits[Code];
```

In this way FruitName will only accept  `'Apple' | 'Pear' | 'Orange'`, pretty cool, right?

## Arrays

Another use case, we could have an array whose values we will need as a type, a solution would be to duplicate the list:

```typescript
const fruits = ['apple', 'pear', 'orange'];
type Fruits = 'apple' | 'pear' | 'orange';
```

Buuut, no ,no, no, duplicate the list is not really correct and maintaining it could be tedious, besides I'm sure we want an elegant solutions, right? how about it looks like this:

```typescript
const fruits = ['apple', 'pera', 'sandia'] as const;
type Fruits = typeof fruits[number];
```

We should stop for a moment to understand a little what happens here:
- `as const` this assigns the values of the array as literal, so, the type of `fruits[0]` is not string it is apple literally, if you want to go deep of this, pls review this [link](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types)
- `fruits[number]` here we are using `indexed-types` again, when using it in arrays with `[number]` allows us to get all the values of the array as a union type, it only works with a array literal.

And thats it, hope this help you 😎