Question

How to Import JSON in TypeScript and Use Typed Properties

Question

I have a JSON file like this:

{
  "primaryBright": "#2DC6FB",
  "primaryMain": "#05B4F0",
  "primaryDarker": "#04A1D7",
  "primaryDarkest": "#048FBE",
  "secondaryBright": "#4CD2C0",
  "secondaryMain": "#00BFA5",
  "secondaryDarker": "#009884",
  "secondaryDarkest": "#007F6E",
  "tertiaryMain": "#FA555A",
  "tertiaryDarker": "#F93C42",
  "tertiaryDarkest": "#F9232A",
  "darkGrey": "#333333",
  "lightGrey": "#777777"
}

I want to import this JSON into a .tsx file. I added this module declaration:

declare module "*.json" {
  const value: any;
  export default value;
}

Then I imported it like this:

import colors = require('../colors.json')

In the file, I try to access a property such as colors.primaryMain, but I get this error:

Property 'primaryMain' does not exist on type 'typeof "*.json"'

How should JSON files be imported correctly in TypeScript so that their properties can be accessed without this error?

Short Answer

By the end of this page, you will understand how JSON imports work in TypeScript, why require and export default can conflict, and how to correctly import JSON in a .ts or .tsx file. You will also learn how to configure TypeScript for JSON modules and how to make imported JSON safer with types.

Concept

TypeScript can import JSON files, but the import style must match how the JSON module is declared and how the compiler is configured.

In this question, the key issue is a mismatch:

  • The declaration says JSON files have a default export.
  • The code uses require(...)-style import syntax.

Those two patterns are different module systems.

Why this matters

In real projects, configuration, theme values, translations, mock data, and metadata are often stored in JSON files. If TypeScript does not understand the shape of the imported file, you may get errors when reading properties such as colors.primaryMain.

The core idea

There are two common ways TypeScript handles JSON:

  1. Modern TypeScript configuration using resolveJsonModule

    • TypeScript reads the JSON file directly.
    • You can import it with standard ES module syntax.
  2. Manual module declaration such as declare module "*.json"

    • You tell TypeScript what a JSON import looks like.
    • Your import syntax must match that declaration.

If your declaration exports default, then your import should be:

import colors from '../colors.json';

Not:

import colors = require('../colors.json');

Best practice today

In most modern TypeScript projects, the preferred approach is:

  • enable resolveJsonModule in tsconfig.json
  • use standard imports
  • optionally define a type for stronger safety

That gives cleaner code and better editor support.

Mental Model

Think of a JSON file as a box of labeled values.

Your colors.json box contains labels like:

  • primaryMain
  • secondaryMain
  • darkGrey

Importing the JSON file is like bringing that box into your code.

But TypeScript also wants a label for the box itself: how is this box exported?

  • If you say, "this box is exported as the default item," then you must pick it up with a default import.
  • If you try to pick it up with a different system, TypeScript may not understand what is inside the box.

So the problem is not the JSON data itself. The problem is that the way you declared the box and the way you imported the box do not match.

Take Quiz

Syntax and Examples

Recommended syntax with resolveJsonModule

In tsconfig.json:

{
  "compilerOptions": {
    "resolveJsonModule": true,
    "esModuleInterop": true
  }
}

Then import the JSON like this:

import colors from '../colors.json';

console.log(colors.primaryMain);

This is the simplest and most common approach.

Using a manual declaration

If you use this declaration:

declare module "*.json" {
  const value: any;
  export default value;
}

Then import like this:

import colors from '../colors.json';

console.log(colors.primaryMain);

Why your original import caused trouble

You used:

import colors = require('../colors.json');

That syntax is CommonJS-style import assignment. It does not match your export default declaration.

Stronger typing example

Instead of any, you can define a type:

type ColorPalette = {
  primaryBright: string;
  primaryMain: string;
  primaryDarker: string;
  primaryDarkest: string;
  secondaryBright: string;
  secondaryMain: string;
  secondaryDarker: string;
  secondaryDarkest: string;
  tertiaryMain: string;
  tertiaryDarker: string;
  tertiaryDarkest: string;
  darkGrey: string;
  lightGrey: string;
};

import colors from '../colors.json';

const palette: ColorPalette = colors;
console.log(palette.primaryMain);

This gives autocomplete and catches missing properties.

Step by Step Execution

Consider this code:

import colors from '../colors.json';

const main = colors.primaryMain;
console.log(main);

Here is what happens step by step:

  1. TypeScript sees import colors from '../colors.json'.
  2. If resolveJsonModule is enabled, TypeScript reads the JSON file and treats it like a module.
  3. The imported object is assigned to the local variable colors.
  4. colors.primaryMain looks up the primaryMain property inside the imported object.
  5. The value "#05B4F0" is assigned to main.
  6. console.log(main) prints the color value.

With your original code:

import colors = require('../colors.json');

TypeScript uses a different module interpretation. Since your declaration described a default export, TypeScript does not connect that cleanly with the require import assignment, so property access can fail at the type level.

Real World Use Cases

JSON imports are used in many practical situations:

Theme configuration

import colors from './colors.json';

const buttonStyle = {
  backgroundColor: colors.primaryMain,
  color: '#fff'
};

App settings

import settings from './settings.json';

if (settings.enableLogging) {
  console.log('Logging is on');
}

Translation files

import en from './locales/en.json';

console.log(en.welcomeMessage);

Mock API data for development

import users from './mock-users.json';

console.log(users.length);

Static metadata

import packageInfo from '../package.json';

console.log(packageInfo.version);

These are all examples where JSON is used as structured static data.

Take Quiz

Real Codebase Usage

In real codebases, developers usually use JSON imports in a few common patterns.

Configuration objects

JSON is often imported once and reused throughout the app:

import colors from './colors.json';

export const theme = {
  primary: colors.primaryMain,
  secondary: colors.secondaryMain
};

Validation after import

If JSON comes from a file that may change, teams often validate it:

import rawConfig from './config.json';

function hasApiUrl(value: any): value is { apiUrl: string } {
  return value && typeof value.apiUrl === 'string';
}

if (!hasApiUrl(rawConfig)) {
  throw new Error('Invalid config.json');
}

Mapping imported JSON into app-specific structures

import colors from './colors.json';

export const palette = {
  brand: colors.primaryMain,
  accent: colors.tertiaryMain,
  text: colors.darkGrey
};

Avoiding any

In production code, any is usually avoided because it removes type safety. A typed interface or inferred type is preferred.

Early failure for bad configuration

Developers often fail fast if imported JSON is missing required values. This avoids hidden bugs later in the app.

Common Mistakes

1. Mixing default exports with require

Broken example:

declare module "*.json" {
  const value: any;
  export default value;
}

import colors = require('../colors.json');
console.log(colors.primaryMain);

Why it fails:

  • The declaration says default export
  • The import uses require syntax

Fix:

import colors from '../colors.json';

2. Forgetting resolveJsonModule

Broken setup:

{
  "compilerOptions": {
    "strict": true
  }
}

If your project relies on direct JSON imports, this may not work unless JSON module resolution is enabled.

Fix:

{
  "compilerOptions": {
    "strict": true,
    "resolveJsonModule": true,
    "esModuleInterop": true
  }
}

3. Using any everywhere

This works, but it removes useful type checking:

declare module "*.json" {
  const value: any;
  export default value;
}

Better approach:

  • use inferred types from resolveJsonModule
  • or assign to a known interface/type

4. Assuming every property exists

Broken example:

import colors from '../colors.json';

console.log(colors.primary);

The JSON does not have primary; it has primaryMain.

Fix:

console.log(colors.primaryMain);

5. Confusing runtime support with TypeScript support

Even if TypeScript accepts a JSON import, your build tool or runtime must also support it. In modern React, Vite, Webpack, and similar tools, this usually works. But the compiler and runtime both matter.

Comparisons

ApproachExampleWhen to useNotes
Default JSON importimport colors from '../colors.json'Best for most modern TypeScript projectsWorks well with resolveJsonModule
Require importconst colors = require('../colors.json')Older CommonJS codebasesLess common in modern TS/React code
Import assignmentimport colors = require('../colors.json')Mostly older TypeScript/CommonJS setupsCan conflict with export default declarations
Manual module declarationdeclare module '*.json'When TypeScript needs help understanding JSON modulesOften unnecessary if resolveJsonModule is enabled

any vs typed object

OptionProsCons
anyQuick and flexibleNo type safety, no useful checking
Explicit type/interfaceSafer, clearer, better autocompleteRequires extra setup
Inferred type from JSONConvenient and often enoughStill depends on file contents staying correct

ES module import vs CommonJS require

FeatureES module importCommonJS require
Syntaximport colors from './colors.json'const colors = require('./colors.json')
Common in modern TS/ReactYesLess often
Matches export defaultYesNot directly
Recommended hereYesNo
Take Quiz

Cheat Sheet

Correct import for JSON with default export

import colors from '../colors.json';

Matching declaration

declare module "*.json" {
  const value: any;
  export default value;
}

Recommended tsconfig.json

{
  "compilerOptions": {
    "resolveJsonModule": true,
    "esModuleInterop": true
  }
}

Accessing properties

console.log(colors.primaryMain);

Avoid this mismatch

import colors = require('../colors.json');

if your declaration uses:

export default value;

Safer typing

type ColorPalette = {
  primaryMain: string;
  secondaryMain: string;
};

import colors from '../colors.json';
const palette: ColorPalette = colors;

Key rule

Your import style must match your module export style.

FAQ

How do I import a JSON file in TypeScript?

Usually like this:

import data from './file.json';

This works best with resolveJsonModule enabled.

Why does TypeScript say a property does not exist on my JSON import?

This often happens because the import syntax does not match the module declaration, or TypeScript is not configured to resolve JSON modules properly.

Do I still need declare module "*.json"?

Often no. In many modern TypeScript projects, resolveJsonModule is enough.

Should I use require to import JSON in TypeScript?

Only in older CommonJS-style codebases. In modern TypeScript and React code, import ... from is usually better.

What does resolveJsonModule do?

It tells TypeScript to treat .json files as modules that can be imported.

Is using any for imported JSON a good idea?

It is convenient, but not ideal. It removes type safety. A typed object or inferred type is safer.

Can I import JSON in a .tsx file?

Yes. A .tsx file can import JSON the same way as a .ts file, as long as the project configuration supports it.

Take Quiz

Mini Project

Description

Build a small theme configuration module that imports a JSON color palette and uses it in TypeScript. This demonstrates correct JSON importing, property access, and optional type checking in a practical UI-style setup.

Goal

Import a JSON palette into TypeScript and expose a typed theme object that uses values such as primaryMain and darkGrey.

Requirements

  • Create a colors.json file with color values.
  • Import the JSON file into a TypeScript file using the correct syntax.
  • Build and export a theme object using values from the JSON.
  • Log at least two theme values to confirm the import works.
Take Quiz

Keep learning

Related questions

View more