Typed-xlsx
Schema Builder

Columns

Defining columns with typed path accessors, function accessors, transforms, and multi-value expansion.

Each column is identified by a stable id and configured with an accessor.

Typed paths

import { 
createExcelSchema
} from "@chronicstone/typed-xlsx";
const
schema
=
createExcelSchema
<{
user
: {
email
: string;
name
: string } }>()
.
column
("name", {
header
: "Name",
accessor
: "user.name",
}) .
column
("email", {
header
: "Email",
accessor
: "user.email",
}) .
build
();

Available path types

The Path<T> utility lists every valid dot-path string for your row type. Hover over UserPaths to see the full union at compile time:

import type { 
Path
} from "@chronicstone/typed-xlsx";
type
User
= {
name
: string;
email
: string;
address
: {
city
: string;
zip
: string };
}; type
UserPaths
=
Path
<
User
>;

Autocomplete on accessor strings

Because accessor is typed as Path<T>, your editor offers completions the moment you open the string. Nested paths like "address." expand into their sub-fields. This works out of the box in VS Code and any LSP-capable editor — no plugin required.

When a path string does not belong to Path<T>, TypeScript rejects it directly at the accessor property — not somewhere downstream. The error message names the valid paths:

import { 
createExcelSchema
} from "@chronicstone/typed-xlsx";
type
User
= {
name
: string };
createExcelSchema
<
User
>()
.
column
("name", {
accessor: "typo", // Error: 'typo' is not assignable to 'name'
No overload matches this call. Overload 1 of 2, '(id: "name", definition: Omit<ColumnDefinition<User, "name">, "id" | "accessor"> & { accessor: "name"; }): SchemaBuilder<User, "name", never, {}>', gave the following error. Type '"typo"' is not assignable to type '"name"'. Overload 2 of 2, '(id: "name", definition: Omit<ColumnDefinition<User, (row: User) => unknown>, "id">): SchemaBuilder<User, "name", never, {}>', gave the following error. Type 'string' is not assignable to type '(row: User) => unknown'.
}) .
build
();

Accessor callbacks

import { 
createExcelSchema
} from "@chronicstone/typed-xlsx";
const
schema
=
createExcelSchema
<{
firstName
: string;
lastName
: string }>()
.
column
("fullName", {
header
: "Full name",
accessor
: (
row
) => `${
row
.
firstName
} ${
row
.
lastName
}`,
}) .
build
();

Accessor type inference

The row parameter is typed to your row type. The value the accessor returns automatically types the transform parameter downstream — no manual annotation needed:

import { 
createExcelSchema
} from "@chronicstone/typed-xlsx";
createExcelSchema
<{
price
: number;
qty
: number }>()
.
column
("total", {
accessor
: (
row
) =>
row
.
price
*
row
.
qty
,
transform
: (
value
) => `$${
value
.
toFixed
(2)}`,
}) .
build
();

The same inference applies when the accessor is a dot-path string — a valid path gives the transform a precise type, an invalid one gives unknown:

import { 
createExcelSchema
} from "@chronicstone/typed-xlsx";
createExcelSchema
<{
cents
: number }>()
.
column
("amount", {
accessor
: "cents",
transform
: (
value
) =>
value
/ 100,
}) .
build
();

Multi-value cells

If an accessor or transform returns an array, typed-xlsx expands the logical row into multiple physical rows and merges single-value columns automatically.

import { 
createExcelSchema
} from "@chronicstone/typed-xlsx";
const
schema
=
createExcelSchema
<{
tags
: string[];
title
: string }>()
.
column
("title", {
accessor
: "title",
}) .
column
("tags", {
accessor
: "tags",
}) .
build
();

Styling and formatting

Static styles are applied to every cell in the column. Pass a callback to compute the style from the row — the row parameter is fully typed:

import { 
createExcelSchema
, type
CellStyle
} from "@chronicstone/typed-xlsx";
const
moneyStyle
:
CellStyle
= {
numFmt
: "$#,##0.00",
alignment
: {
horizontal
: "right" },
}; const
schema
=
createExcelSchema
<{
amount
: number;
status
: "paid" | "pending" }>()
.
column
("amount", {
accessor
: "amount",
style
:
moneyStyle
,
}) .
column
("status", {
accessor
: "status",
style
: (
row
) => ({
font
: {
bold
: true,
color
: {
rgb
:
row
.
status
=== "paid" ? "166534" : "B42318" },
}, }), }) .
build
();
Copyright © 2026 Cyprien Thao. Released under the MIT License.