DRY Typescript types
Tags: dry, typescript, types
Published: 2021-01-25 16:12:32

---
title: DRY Typescript types
published: true
description: Don't repeat yourself, reuse your types.
tags: dry, typescript, types
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/zhuby4xy311s3o0v4p7a.jpg
---

Typescript gives us a few tools that we can use to reference existing types, which is very useful if we want to be consistent across our codebase.

Let's see a few examples:

> _Attention: contrived examples ahead._

# Indexed type access

Say we have an interface like this one:

```ts
export interface User {
    username: string;
    age: number;
    fullName: {
        firstname: string;
        lastname: string;
    }
}
```

We can reference all those types inside `User` by using index syntax:

```ts
let userAge: User['age']; // number
let fullName: User['fullName']; // { firstname: string; lastname: string; }
let lastname: User['fullName']['lastname']; // string
```

This also works for function signatures, take a look at the `fullName` parameter:

```ts
function setFullName (user: User, fullName: User['fullName']): User {
    return {
        ...user,
        fullName
    };
};
```

Class methods can also be targetted with index syntax, the whole signature or just the return type, which is useful when some method uses a complex return type that doesn't reference any exported type:

```ts
class MyClass {
    myMethod() {
        return {
            foo: 'bar'
        }
    }
}

let myMethod: MyClass['myMethod'] // () => {foo: string;}
let myReturn: ReturnType<MyClass['myMethod']> // {foo: string;}
```

# Indexed type access + instances

We can also apply the same techniques we've seen so far within the realm of instances thanks to the `typeof` operator:

```ts
const user = {
    username: 'picklerick',
    age: 70,
    fullName: {
        firstname: 'Rick',
        lastname: 'Sanchez'
    }
}

let fullName: typeof user['fullName'] // { firstname: string; lastname: string; }
```

Last but not least, `typeof` with class instances and function signatures:

```ts
class MyClass {
    prop = 'bar';
    method() {
        return {
            foo: this.prop
        }
    }
}
const myClass = new MyClass();
let myProp: typeof myClass['prop'] // string
let myMethod: typeof myClass['method'] // () => {foo: string;}
let myReturn: ReturnType<typeof myClass['method']> // {foo: string;}
```

# Indexed type access + Generics

Generic types are inferred, so everything works the same:

```ts
interface Action<T> {
    type: string;
    payload: T;
}

interface User{
    id: string;
    name: string;
}

let addUserAction: Action<User>; // {type:string; payload: {id:string; name:string}}
let payload : typeof addUserAction['payload'] // User
```

# Indexed type access + tuples
Tuples have similar syntax, but indexes are numbers instead of strings:

```ts
type MyTuple = [number, string];

let fst: MyTuple[0] // number
let snd: MyTuple[1] // string
let nope: MyTuple[3] // Error: Tuple type 'MyTuple' of length '2' has no element at index '3'.
```

We can also use the `typeof` operator here:

```ts
const myTupleValue: MyTuple = [3, 'hello'];
let fst: typeof myTupleValue[0] // number
let snd: typeof myTupleValue[1] // string
```

But we have to be explicit with the tuple type otherwise, what used to be a tuple becomes an array and the outcome is very different:

```ts
const myTupleValue = [5, 'hello'];
let fst: typeof myTupleValue[0] // string | number
let snd: typeof myTupleValue[1] // string | number
let yep: typeof myTupleValue[3] // string | number
```

# Working with keys
Type keys are also accessible thanks to the `keyof` operator:

```ts
interface User {
    username: string;
    age: number;
}

let userKeys: keyof User // "username" | "age"
```

And, as you may have guessed, our friend `typeof` helps us with instances again:

```ts
const user = {
    username: 'picklerick',
    age: 70
}

let userKeys: keyof typeof user // "username" | "age"
```

# Wrapping up

Creating new types with Typescript is super easy and cheap thanks to its structural typing nature, but that doesn't mean we should be careless about that. Having these techniques in our toolbelt can help us keep consistency across our codebase.