Skip to Content
Type an Object Without Copy-Pasting the Shape Twice
Beginner
0 likes
Tutorials

Type an Object Without Copy-Pasting the Shape Twice

Write an object shape once with type, derive one from an existing object with typeof, and share it between files with import type. After this, a renamed property shows you every place to fix.

You wrote { title: string; price: number } in one function. Then again in the next one. A week later someone adds a field to one of them and the other is quietly out of date. The fix is to write the shape once and give it a name.

The problem: two copies

function label(product: { title: string; cost: number }): string {
  return product.title + " costs " + product.cost;
}

function withTax(product: { title: string; price: number }): number {
  return product.price * 1.12;
}

const pen = { title: "Pen", price: 15 };

console.log(label(pen));
console.log(withTax(pen));
copies.ts(11,19): error TS2741: Property 'cost' is missing in type '{ title: string; price: number; }' but required in type '{ title: string; cost: number; }'.

Someone renamed price to cost in label and forgot withTax, or the other way around. The compiler catches it here because both functions receive the same object. With separate files and separate objects, you would only find out when the two meet. And every future change means finding every copy.

Step 1: write the shape once with type

type Product = {
  title: string;
  price: number;
};

function label(product: Product): string {
  return product.title + " costs " + product.price;
}

function withTax(product: Product): number {
  return product.price * 1.12;
}

const pen: Product = { title: "Pen", price: 15 };

console.log(label(pen));
console.log(withTax(pen).toFixed(2));
Pen costs 15
16.80

Product is a name for the shape. Change price in the one place, and the compiler reports every function and every object that no longer fits. That list is your to-do list for the rename.

Step 2: let an existing object be the source

Sometimes you already have the object, such as a default configuration. Do not describe it a second time. Ask for its type with typeof.

const defaults = {
  currency: "PHP",
  decimals: 2,
  showSymbol: true,
};

type Settings = typeof defaults;

function format(amount: number, settings: Settings = defaults): string {
  return amount.toFixed(settings.decimals) + " " + settings.currency;
}

console.log(format(10));
console.log(format(10, { currency: "USD", decimals: 0, showSymbol: false }));
10.00 PHP
10 USD

typeof defaults here is the TypeScript type operator, not the JavaScript one you used for narrowing. It takes the type the compiler already inferred for defaults. If you add a property to the object, Settings gains it too.

⚠ Warning: The inferred type is what the values look like, not what they might be. currency: "PHP" inferred as string, so "USD" is fine. If you want only a fixed list of codes, write a union of literals and use it explicitly.

Step 3: share it between files

Once two files need the same shape, put it in its own file and export it.

export type Product = {
  title: string;
  price: number;
};
import type { Product } from "./types.js";

const pen: Product = { title: "Pen", price: 15 };
console.log(pen.title, pen.price);
{
  "compilerOptions": {
    "target": "es2022",
    "module": "nodenext",
    "strict": true,
    "rootDir": "src",
    "outDir": "dist"
  },
  "include": ["src"]
}
npx tsc
node dist/index.js
Pen 15

import type says this import exists only for the compiler. It is erased from the output, so it cannot create a circular import at run time. Notice the path ends in .js, not .ts. That looks wrong, but with nodenext you write the name of the file that will exist after compiling, and TypeScript maps it back to the .ts file.

What to avoid

  • Do not type the object as object or {}. You lose the property names.
  • Do not copy the type into a comment so you can remember it. Write it once as a type.
  • Do not create Product2 when the shape changes. Change Product, and let the compiler show you what breaks.

Related course: TypeScript for Beginners.

About

Write an object shape once with type, derive one from an existing object with typeof, and share it between files with import type. After this, a renamed property shows you every place to fix.

Responsible
John G
Last Update
10/20/2026
Reading Time
4 min
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.