---
title: Bitovi Academy - Conditional Types
description: Learn how to create new types to simplify functions and enforce type safety with conditional types!
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting?hsLang=en-us)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting?hsLang=en-us)
- ![Project management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project management](https://www.bitovi.com/services/agile-project-management-consulting?hsLang=en-us)
- ![Product design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product design](https://www.bitovi.com/services/product-design-consulting?hsLang=en-us)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services?hsLang=en-us)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting?hsLang=en-us)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers?hsLang=en-us)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting?hsLang=en-us)
- [Design Systems](https://www.bitovi.com/services/axure-figma-migration?hsLang=en-us)
- [React](https://www.bitovi.com/services/frontend/react-consulting?hsLang=en-us)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting?hsLang=en-us)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native?hsLang=en-us)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting-1?hsLang=en-us)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study?hsLang=en-us)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign?hsLang=en-us)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work?hsLang=en-us)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source?hsLang=en-us)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about perfecting software delivery
  
  ](https://bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships?hsLang=en-us)
- [![Academy](https://www.bitovi.com/hubfs/limbo/icons/icon-academy.svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy/?hsLang=en-us)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse our tools or contribute to our open source mission.
  
  ](https://www.bitovi.com/open-source?hsLang=en-us)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

- [ Advanced JavaScript ](https://www.bitovi.com/academy/learn-advanced-javascript.html?hsLang=en-us)
- [ DOM and jQuery ](https://www.bitovi.com/academy/learn-dom-jquery.html?hsLang=en-us)
- [ Debug JavaScript ](https://www.bitovi.com/academy/learn-to-debug-javascript.html?hsLang=en-us)
- [ Learn TypeScript ](https://www.bitovi.com/academy/learn-typescript.html?hsLang=en-us)
- [ Learn React Native ](https://www.bitovi.com/academy/learn-react-native.html?hsLang=en-us)
- [ Learn Web Components ](https://www.bitovi.com/academy/learn-web-components.html?hsLang=en-us)
- [ Agile Program Management With Jira ](https://www.bitovi.com/academy/learn-agile-program-management-with-jira.html?hsLang=en-us)
- [ Learn RxJS ](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us)
- [ Giving a Training ](https://www.bitovi.com/academy/training.html?hsLang=en-us)
- [ Learn Technology Consulting ](https://www.bitovi.com/academy/learn-technology-consulting.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react.html?hsLang=en-us)
- [ Learn NgRx ](https://www.bitovi.com/academy/learn-ngrx.html?hsLang=en-us)
- [ Learn Graphql ](https://www.bitovi.com/academy/learn-graphql.html?hsLang=en-us)
- [ Learn Docker ](https://www.bitovi.com/academy/learn-docker.html?hsLang=en-us)
- [ Learn CanJS ](https://www.bitovi.com/academy/learn-canjs.html?hsLang=en-us)
- [ Learn Angular ](https://www.bitovi.com/academy/learn-angular.html?hsLang=en-us)
- [ Advanced TypeScript ](https://www.bitovi.com/academy/advanced-typescript.html?hsLang=en-us) 
    - [ Typing Systems ](https://www.bitovi.com/academy/advanced-typescript/typing-systems.html?hsLang=en-us)
    - [ Generics With Constraints ](https://www.bitovi.com/academy/advanced-typescript/generics-with-constraints.html?hsLang=en-us)
    - [ Index Accessed Types ](https://www.bitovi.com/academy/advanced-typescript/index-accessed-types.html?hsLang=en-us)
    - [ Mapped Types ](https://www.bitovi.com/academy/advanced-typescript/mapped-types.html?hsLang=en-us)
    - [ Conditional Types ](https://www.bitovi.com/academy/advanced-typescript/conditional-types.html?hsLang=en-us)
    - [ Template Literal Types ](https://www.bitovi.com/academy/advanced-typescript/template-literal-types.html?hsLang=en-us)

[View More Courses](https://www.bitovi.com/academy/#courses) [ ]

# Conditional Types `page`

Learn how to create new types to simplify functions and enforce type safety with conditional types!

## Overview

In this section, we will take a look at `any` and `never` again, the roles they play within TypeScript’s type system, along with their impact when mixed in with other types. We will also look at conditional types, what they are, how they behave, and how they can make our function signatures simpler with little overhead by defining complex types. Finally, we will discuss another use of conditional types and introduce a new syntax – `infer` – which makes conditional types even more powerful.

## Top and Bottom Types

Within type systems there exists a top type and a bottom type. A top type contains all types, meaning any other type is assignable to it. A bottom type is assignable to nothing. Going back to thinking of types in TypeScript as sets, the top type would be a superset containing all the other types; the bottom type would be the empty set containing nothing. TypeScript has two top types – `any` and `unknown` and a single bottom type `never`.

We briefly touched on `any` and `never` in the introductory course. As a quick recap, any variable assigned type `any` essentially opts out of typing, as it can be anything. `unknown` is just like any but the only thing assignable to it is `any`.

```
let anything: any = 1;

anything = "hello world";
anything = {};
anything = [1, 2, 3];
anything = new Promise(() => {});
```

`never` is not assignable to anything. Two common cases when never shows up are a throwing function…

```
function throwError(message: string): never {
  throw new Error(message);
}
```

…and when TypeScript has exhausted all possible cases and determines a block of code won’t run:

```
function primaryColorsToHexMessage(primaryColor: "red" | "blue" | "yellow") {
  switch (primaryColor) {
    case "red":
      return primaryColor + " is 0xFF0000";
    case "blue":
      return primaryColor + " is 0x00FF00";
    case "yellow":
      return primaryColor + " is 0xFFFF00";
    default:
      primaryColor; // primaryColor is never here.
  }
}
```

`any` and `never` have unique impacts on the set operators we use to create types in TypeScript. When we union any type with `any` the resulting type will be `any` and if we union a type with `never` the resulting type will be whatever else is in the union.

```
type UnionWithAny = string | any; // any
type UnionWithNever = string | never; // string
```

Type intersections with `any` behave in a similar way – a type intersected with `any` is `any`. `never` has a different behavior though and a type intersected with `never` is `never`.

```
type IntersectionWithAny = string & any; // any
type IntersectionWithNever = string & never; // never
```

Unions with bottom types will be especially important for us moving forward as we talk about conditional types.

## Conditional Types

Conditional types act exactly as conditional statements do in programming – the output is based on whether or not an input satisfies a given condition. Conditional types allow us to define different types based on the type passed in as an input. The syntax for conditional types mimics that of a JavaScript ternary and the condition is specified just like a constraint on a generic.

```
type extends OtherThing ? TypeIfConditionIsMet : TypeIfConditionIsNotMet
```

One of the best ways to illustrate the utility of conditional typing is to see how it can help simplify overloaded functions. Take the `createBattle` function shown below.

```
type TrainerBattle = {
  challenger: string;
};

type WildPokemonBattle = {
  challengingPokemon: string;
};

type GymLeaderBattle = {
  gymLeader: string;
  rewards: object;
};

function createBattle(battle: "trainer-battle"): TrainerBattle;
function createBattle(battle: "wild-pokemon-battle"): WildPokemonBattle;
function createBattle(
  battle: "trainer-battle" | "wild-pokemon-battle"
): TrainerBattle | WildPokemonBattle {
  // Implementation detail
}

const trainer = createBattle("trainer-battle"); // Type is TrainerBattle
const wild = createBattle("wild-pokemon-battle"); // Type is WildPokemonBattle
```

The function overloads show we want the output type for the function to be based on the type put in. In this case, if `"trainer-battle"` is input, `TrainerBattle` should be the output; if `"wild-pokemon-battle"` is input, `WildPokemonBattle` should be output. We can use generics and conditional types to simplify this function signature.

```
type BattleTypes = "trainer-battle" | "wild-pokemon-battle";

type Battle<T extends BattleTypes> = T extends "wild-pokemon-battle"
  ? WildPokemonBattle
  : TrainerBattle;

function createBattle<T extends BattleTypes>(battle: T): Battle<T> {
  // Implementation detail
}

const trainer = createBattle("trainer-battle"); // Type is TrainerBattle
const wild = createBattle("wild-pokemon-battle"); // Type is WildPokemonBattle
```

The magic here happens in the `Battle` conditional type. In `Battle` we look for whichever `BattleType` is passed in. If it’s `"wild-pokemon-battle"` we resolve to `WildPokemonBattle`, otherwise we resolve to `TrainerBattle`. Another cool feature of conditional types is that they are nestable. To demonstrate this, let’s take this battle situation a step further and make a couple of adjustments. Let’s add a third battle type.

```
type TrainerBattle = {
  challenger: string;
};

type WildPokemonBattle = {
  challengingPokemon: string;
};

type GymLeaderBattle = {
  gymLeader: string;
  rewards: object;
};

type BattleTypes =
  | "trainer-battle"
  | "wild-pokemon-battle"
  | "gym-leader-battle";
```

How then would we update our conditional type? Well, it turns out we can update the conditionals just like we would when we nest JavaScript ternaries.

```
type Battle<T extends _BattleTypes> = T extends "trainer-battle"
  ? TrainerBattle
  : T extends "wild-pokemon-battle"
  ? WildPokemonBattle
  : GymLeaderBattle;
```

And just like that, we’ve added another possible battle without having to touch the createBattle function signature.

```
const trainer = createBattle("trainer-battle"); // Type is TrainerBattle
const wild = createBattle("wild-pokemon-battle"); // Type is WildPokemonBattle
const gym = createBattle("gym-leader-battle"); // Type is GymLeaderBattle
```

## Conditional Types With Unions

Conditional types shine when it comes to refining unions into more distilled types. When given a union, conditional types distribute the condition to each member of the union. One of the simplest applications of this is the `NonNullable<T>` utility type provided by TypeScript. `NonNullable` creates a new type by removing `null` and `undefined` from the type passed into it.

```
type MaybeStringOrNumber = string | number | undefined | null;

type StringOrNumber = NonNullable<MaybeStringOrNumber>; // string | number
```

Below is the definition of `NonNullable`.

```
/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T extends null | undefined ? never : T;
```

The definition may look complicated, but as we did with mapped types, let’s remove some of the noise and break it down bit by bit to see how this works. Let’s start by placing the union into `NonNullable` directly.

```
type StringOrNumber = NonNullable<string | number | undefined | null>;
```

Since we passed in a union, TypeScript will distribute the `NonNullable` to each member of the union.

```
type StringOrNumber =
  | NonNullable<string>
  | NonNullable<number>
  | NonNullable<undefined>
  | NonNullable<null>;
```

From here we can remove the generics and each of the `NonNullable` can be rewritten as a conditional.

```
type StringOrNumber =
  | (string extends null | undefined ? never : string)
  | (number extends null | undefined ? never : number)
  | (undefined extends null | undefined ? never : undefined)
  | (null extends null | undefined ? never : null);
```

Each of these conditionals can then be evaluated.

```
type StringOrNumber = string | number | never | never;
```

As we discovered in the first section, `never` doesn’t impact the results of the union and can be removed. Removing the `never`s from the union leaves us with our final result.

```
type StringOrNumber = string | number;
```

The refinement aspects of conditional types become even stronger when used together with other TypeScript features we’ve seen so far. Let’s do a little more tweaking to our types from the `createBattle` example above and define a function called `emitBattleStart` that can take a battle name and a payload that corresponds to the properties in the named typed.

```
emitBattleStart("wild-pokemon-battle", { challengingPokemon: "onix" });
```

Before we start looking at the `emitBattle` function let’s make our types a little more functional. Instead of having `BattleTypes` separated from the rest of the battle types, we could use them as literals on our battle types to create a discriminating union.

```
type TrainerBattle = {
  battleType: "trainer-battle";
  challenger: string;
};

type WildPokemonBattle = {
  battleType: "wild-pokemon-battle";
  challengingPokemon: string;
};

type GymLeaderBattle = {
  battleType: "gym-leader-battle";
  gymLeader: string;
  rewards: object;
};

type PokemonBattles = TrainerBattle | WildPokemonBattle | GymLeaderBattle;
```

> If you’re curious about how this might impact the createBattle function types we defined previously, those could now be rewritten as…
> 
> ```
> type Battle<T extends PokemonBattles["battleType"]> =
>   T extends "trainer-battle"
>     ? TrainerBattle
>     : T extends "wild-pokemon-battle"
>     ? WildPokemonBattle
>     : GymLeaderBattle;
> 
> function createBattle<T extends PokemonBattles["battleType"]>(
>   battle: T
> ): Battle<T> {
>   // Implementation detail
> }
> ```

To create our `emitBattleStart` function let’s first start by getting the first parameter in place.

```
function emitBattleStart<BattleType extends PokemonBattles["battleType"]>(
  battleType: BattleType,
  battleInformation: BattleInfomation // ??? To be defined below
) {
  /** ... */
}
```

The next part is where it gets tricky. Somehow we need to get the correct object shape for the battle information. We can break it down like this. First, we need to select the member of the `PokemonBattles` union that corresponds to the `BattleType` from the first parameter of the function. Second, we need to remove the `battleType` key from that type. And finally, we need to map over the new keys, making sure they have the same values.

Starting with the first step, let’s find a way to select the correct member of the `PokemonBattles` union. We can accomplish this with our good friend conditional types. We can use generics to give our `BattleInformation` type access to the `PokemonBattles` union and the `BattleType` and inside it uses a conditional type to refine the union to being the battle type we’re after.

```
type BattleInformation<BattleType, Battle> = Battle extends {
  battleType: BattleType;
}
  ? Battle
  : never;
```

> If this looks a little complicated it helps to throw one of the `battleTypes` in there real quick to get a better feel for it.
> 
> ```
> type WildBattleFromUnion = BattleInformation<
>   "wild-pokemon-battle",
>   PokemonBattles
> >;
> ```
> 
> which inside the `BattleInformation` type looks like…
> 
> ```
> TrainerBattle | WildPokemonBattle | GymLeaderBattle
>   extends {battleType: 'wild-pokemon-battle'} ? Battle : never
> ```

Next, we need a way to get rid of the `battleType` key from this new type. Luckily for us, TypeScript provides a utility type that does just that – `Exclude`. Exclude takes two unions and **excludes** the members of the second union from the first. As you might have guessed, `Exclude` uses conditional types under the hood to provide this functionality. For our case, we want to exclude `battleType` from the keys of the battle.

```
Exclude<keyof Battle, "battleType">;
```

Our final step is to map over these and reconstruct the type. To do this, let’s define a `FormatBattle` type that does this for us and pass our refined `Battle` type into it.

```
type FormatBattle<Battle> = {
  [FilteredKey in Exclude<keyof Battle, "battleType">]: Battle[FilteredKey];
};

type BattleInformation<BattleType, Battle> = Battle extends {
  battleType: BattleType;
}
  ? FormatBattle<Battle>
  : never;
```

With that, we have finished up our typing issues! Our function now has type-safety and we can use it as we desire.

```
function emitBattleStart<BattleType extends PokemonBattles["battleType"]>(
  battleType: BattleType,
  battleInformation: BattleInfomation<BattleType, PokemonBattles>
){ /** ... */}

emitBattleStart("wild-pokemon-battle", {challengingPokemon: 'onix'});
emitBattleStart("trainer-battle", {challenger: 'gary'})
emitBattleStart(
  "gym-leader-battle",
  {
    gymLeader: "Misty"
    rewards: {badge: 'Cascade Badge'}
  }
)
```

That said, we can take it a little bit further and add an alias and default to help make the typing a bit more semantic. It feels a little weird needing to pass in `PokemonBattles`, and the functionality of the type and how it’s used seem to differ a bit. One extra type we can resolve this. Let’s update `BattleInformation` to alias our conditional mapping and give a more semantically relevant name like `GetBattleInformation`.

```
type FormatBattle<Battle> = {
  [FilterKey in Exclude<keyof Battle, "battleType">]: Battle[FilterKey];
};

type GetBattleInformation<BattleType, Battle> = Battle extends {
  battleType: BattleType;
}
  ? FormatBattle<Battle>
  : never;

type BattleInformation<
  BattleType,
  Battles = PokemonBattles
> = GetBattleInformation<BattleType, Battles>;

function emitBattleStart<BattleType extends PokemonBattles["battleType"]>(
  battleType: BattleType,
  battleInformation: BattleInformation<BattleType>
) {
  //
}
```

## A New and Powerful Syntax

Another use case of conditional types is to give us access to types we wouldn’t normally have access to by allowing us to unwrap types. A greater example of this is an `ArrayElement` type which checks if the type is an array and if it is, uses index accessed types to grab the shape inside.

```
type ArrayElement<T> = T extends Array<any> ? T[number] : never;
```

This type of usage is so common that TypeScript added an `infer` keyword that allows us to define a new generic variable within the extends clause of a conditional type to be used in our different paths.

```
type ArrayElement<T> = T extends Array<infer ElementType> ? ElementType : never;
```

`infer` powers many utility types in TypeScript like `ReturnType` and `Parameters`.

```
/**
 * Obtain the parameters of a function type in a tuple
 */
type Parameters<T extends (...args: any) => any> = T extends (
  ...args: infer P
) => any
  ? P
  : never;

/**
 * Obtain the return type of a function type
 */
type ReturnType<T extends (...args: any) => any> = T extends (
  ...args: any
) => infer R
  ? R
  : any;
```

Conditional type’s refinement makes it a powerful utility. We’ve seen how conditional types can be used to simplify function signatures and create robust types for complex functions. Conditional types and `infer` will play a big role in our last section: template literal types.

## Exercises

### Exercise 1

We used exclude in one of the examples in the content of this section. Let’s take a moment to create the type ourselves. Exlude takes two generics `T` and `U` and removes the memebers in `U` from `T`.

```
type WildPokemonBattle = {
  battleType: "wild-pokemon-battle";
  challengingPokemon: string;
};

type WildPokemonBattleNoBattleType = _Exclude<
  keyof WildPokemonBattle,
  "battleType"
>; // "challengingPokemon"
```

[Open in CodeSandbox](https://codesandbox.io/s/1gvoo5?file=/05-conditional-types-ex-01.ts)

```
/**
 * Exercise 1
 *
 * We used exclude in one of the examples in the content of this section.
 * Let’s take a moment to create the type ourselves. Exlude takes two generics
 * `T` and `U` and removes the memebers in `U` from `T`.
 *
 * ```ts
 * type WildPokemonBattle = {
 *   battleType: "wild-pokemon-battle";
 *   challengingPokemon: string;
 * };
 *
 * type WildPokemonBattleNoBattleType = _Exclude<keyof WildPokemonBattle, "battleType">; // "challengingPokemon"
 * ```
 */
type _Exclude<T, U> = any;

```

Click to see the solution

```
type _Exclude<T, U> = T extends U ? never : T;

```

### Exercise 2

Let’s build out an example similar to `ArrayElement` provided by the TypeScript documentation (No cheating by looking it up!)

`Flatten` should a new type that unnests arrays by one level.

```
type FlattenedStringArray = Flatten<string[]>; // string
type FlatString = Flatten<string>; // string

type NestedNumberArray = Flatten<Array<Array<number>>>; // number []
```

[Open in CodeSandbox](https://codesandbox.io/s/r5ch7w?file=/05-conditional-types-ex-02.ts)

```
/**
 Exercise 2
 *
 * Let’s build out an example similar to `ArrayElement` provided by the TypeScript documentation (No cheating by looking it up!)
 *
 * `Flatten` should create a new type that unnests arrays by one level.
 *
 * ```ts
 * type FlattenedStringArray = Flatten<string[]> // string
 * type FlatString = Flatten<string> // string
 *
 * type NestedNumberArray = Flatten<Array<Array<number>>> // number []
 * ```
 */
type Flatten<T> = any;

type FlattenedStringArray = Flatten<string[]>; // string
type FlatString = Flatten<string>; // string
type NestedNumberArray = Flatten<Array<Array<number>>>; // number []

```

Click to see the solution

```
export type Flatten<T> = T extends Array<infer R> ? R : T;

```

###### On this page...

###### Get help

If you need [help](https://discord.gg/J7ejFsZnJ4) with an exercise, please reach out to us on [Discord](https://discord.gg/J7ejFsZnJ4)

If you find a bug, please [create an issue](https://github.com/bitovi/academy/issues/new) or email [contact@bitovi.com](mailto:contact@bitovi.com?Subject=Training%20Suggestion)

## Join the Bitovi Newsletter

 Do you want to receive updates about new Bitovi Academy courses, Bitovi open source projects, and dev community news? If so, please provide your email. We won’t spam you or give it away for any reason!  
*By providing your email you agree to receive communications from Bitovi*

![](https://bitovi.github.io/academy/static/img/close.svg)

```json
{
     "@context": "http://schema.org",
     "@type": "Organization",
     "mainEntityOfPage":{
          "@type":"WebPage",
          "@id":"https://www.bitovi.com/academy/advanced-typescript/conditional-types.html",
          "description": "Learn how to create new types to simplify functions and enforce type safety with conditional types! 
"
     },
     "url": "http://bitovi.com",
     "logo": "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
     "image": "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
     "name": "Bitovi Web App Consulting",
     "alternateName": "Bitovi",
      "naics": "541511",
      "description": "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
     "address": {
          "@type": "PostalAddress",
          "streetAddress": "1134 Pine Tree Lane ",
          "addressLocality": "Libertyville",
          "addressRegion": "IL",
          "addressCountry": "United States",
          "postalCode": "60048"
     },
     "areaServed": {
          "@type": "GeoCircle",
          "geoMidpoint": {
               "@type": "GeoCoordinates",
               "latitude": "41.8781",
               "longitude": "87.6298"
          },
          "geoRadius": "5000 km"
     },
     "telephone": "312-620-0386",
     "email": "contact@bitovi.com",
     "sameAs": [
          "https://www.facebook.com/BitoviLLC/",
          "https://twitter.com/bitovi",
          "https://www.linkedin.com/company/bitovi"
     ]
}
```