{"id":8863800,"url":"https://github.com/ChronicStone/typed-xlsx","last_synced_at":"2025-08-09T19:31:40.247Z","repository":{"id":210478750,"uuid":"726289659","full_name":"ChronicStone/typed-xlsx","owner":"ChronicStone","description":"A simple yet powerful library to effortlessly export any data into XLSX sheets, with the full power of type-safety and awesome DX","archived":false,"fork":false,"pushed_at":"2024-07-21T09:07:57.000Z","size":14443,"stargazers_count":136,"open_issues_count":2,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-07T16:02:32.550Z","etag":null,"topics":["excel","excel-export","export","js-to-xlsx","js-xlsx","json-as-xlsx","json-export","json-to-xlsx","json-xlsx","sheetjs","ts-xlsx","type-safe","type-safety","typescript","typescript-xlsx","xls","xlsx"],"latest_commit_sha":null,"homepage":"https://typed-xlsx.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChronicStone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["antfu"]}},"created_at":"2023-12-02T00:33:08.000Z","updated_at":"2024-10-24T07:41:15.000Z","dependencies_parsed_at":"2023-12-03T05:27:33.260Z","dependency_job_id":"868ff723-e62c-4cdc-93e9-ae336d758fa7","html_url":"https://github.com/ChronicStone/typed-xlsx","commit_stats":null,"previous_names":["chronicstone/sweet-json-xlsx","chronicstone/typed-xlsx"],"tags_count":16,"template":false,"template_full_name":"antfu/starter-ts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Ftyped-xlsx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Ftyped-xlsx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Ftyped-xlsx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Ftyped-xlsx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChronicStone","download_url":"https://codeload.github.com/ChronicStone/typed-xlsx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229316110,"owners_count":18054145,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["excel","excel-export","export","js-to-xlsx","js-xlsx","json-as-xlsx","json-export","json-to-xlsx","json-xlsx","sheetjs","ts-xlsx","type-safe","type-safety","typescript","typescript-xlsx","xls","xlsx"],"created_at":"2024-04-30T23:08:23.872Z","updated_at":"2024-12-12T01:30:35.904Z","avatar_url":"https://github.com/ChronicStone.png","language":"TypeScript","funding_links":["https://github.com/sponsors/antfu"],"categories":["TypeScript"],"sub_categories":[],"readme":"# typed-xlsx\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![bundle][bundle-src]][bundle-href]\n[![JSDocs][jsdocs-src]][jsdocs-href]\n[![License][license-src]][license-href]\n\n\n\n\n\u003e ### **Export any data into xls/xlsx files effortlessly, while benefiting from great type-safety \u0026 developper experience.**\n\n## Key Features :\n\n- 🛠 **Type-safe Schema Builder:** Design your spreadsheet schema with strong typing for enhanced reliability and developer experience.\n\n- 🔄 **Type-safe Data Serialization \u0026 Transformation:** Ensure data integrity through type-safe serialization and transformation functionalities.\n\n- 🔧 **Shared Type-safe Custom Value Pre-processors:** Utilize shared pre-processors for consistent value transformaiton\n\n- 🧮 **Column Summary :** Auto-insert computed column summaries for efficient data analysis and overview.\n\n- 🧩 **Complex Row Structures with Auto-Merging:** Implement advanced row layouts with sub-rows for automatic row merging / styling for seamless data organization and display.\n\n- 🎯 **Easy Default Values Management:** Manage default values effortlessly, ensuring your data is presented exactly as you intend.\n\n- 📊 **Dynamic Column Selection:** Selectively choose which columns of the schema to use when building a table\n\n- 🗺️ **Dynamic Column Mapping with Type-safe Context:** Map columns dynamically with a type-safe context, injected when building sheet\n\n- 🎨 **Dynamic Cell Styling/Formatting:** Customize cell styling and formatting dynamically per-row with ease\n\n- 📑 **Multi-sheet Support:** Create spreadsheets with multiple sheets\n\n- 🏗️ **Multiple Tables Per Sheet Support:** Include as many tables you need inside a same sheet\n\n- 🌐 **Linear or Grid-like Layout for Sheets with Multiple Tables:** Choose between linear or grid layouts for sheets\n\n## INSTALLATION\n```bash\npnpm add @chronicstone/typed-xlsx\n```\n\n## USAGE EXAMPLE\n\n#### 1. Define the type of exported data (Or infer it from a function / a db query, or wherever you want) :\n```ts\ninterface Organization {\n  id: number\n  name: string\n}\n\ninterface User {\n  id: number\n  firstName: string\n  lastName: string\n  email: string\n  roles: string[]\n  organizations: Organization[]\n  results: {\n    general: { overall: number }\n    technical: { overall: number }\n    interview?: { overall: number }\n  }\n}\n```\n\n#### 2. Build a sheet schema :\n```ts\nimport { ExcelSchemaBuilder } from '@chronicstone/typed-xlsx'\n\n// OPTIONAL : DEFINE SHARED TRANSFORMERS THAT CAN BE USE TO TRANSFORM VALUE INSERTED INTO A CELL\nconst transformers = {\n  boolean: (value: boolean) =\u003e value ? 'Yes' : 'No',\n  list: (value: (string)[]) =\u003e value.join(', '),\n  arrayLength: (value: any[]) =\u003e value.length,\n} satisfies TransformersMap\n\n// Use the schema builder to define your sheet schema\nconst userExportSchema = ExcelSchemaBuilder\n  .create\u003cUser\u003e()\n  .withTransformers(transformers)\n  .column('id', {\n    key: 'id',\n    summary: [{ value: () =\u003e 'TOTAL BEFORE VAT' }, { value: () =\u003e 'TOTAL' }],\n  })\n  .column('firstName', { key: 'firstName' })\n  .column('lastName', { key: 'lastName' })\n  .column('email', { key: 'email' })\n  .column('roles', {\n    key: 'roles',\n    transform: 'list',\n    cellStyle: data =\u003e ({ font: { color: { rgb: data.roles.includes('admin') ? 'd10808' : undefined } } }),\n  })\n  .column('balance', {\n    key: 'balance',\n    format: '\"$\"#,##0.00_);\\\\(\"$\"#,##0.00\\\\)',\n    summary: [\n      {\n        value: data =\u003e data.reduce((acc, user) =\u003e acc + user.balance, 0),\n        format: '\"$\"#,##0.00_);\\\\(\"$\"#,##0.00\\\\)',\n      },\n      {\n        value: data =\u003e data.reduce((acc, user) =\u003e acc + user.balance, 0) * 1.2,\n        format: '\"$\"#,##0.00_);\\\\(\"$\"#,##0.00\\\\)',\n      },\n    ],\n  })\n  .column('nbOrgs', { key: 'organizations', transform: 'arrayLength' })\n  .column('orgs', { key: 'organizations', transform: org =\u003e org.map(org =\u003e org.name).join(', ') })\n  .column('generalScore', {\n    key: 'results.general.overall',\n    format: '# / 10',\n    summary: [{\n      value: data =\u003e data.reduce((acc, user) =\u003e acc + user.results.general.overall, 0) / data.length,\n      format: '# / 10',\n    }],\n  })\n  .column('technicalScore', {\n    key: 'results.technical.overall',\n    summary: [{\n      value: data =\u003e data.reduce((acc, user) =\u003e acc + user.results.technical.overall, 0) / data.length,\n    }],\n  })\n  .column('interviewScore', { key: 'results.interview.overall', default: 'N/A' })\n  .column('createdAt', { key: 'createdAt', format: 'd mmm yyyy' })\n  .group('group:org', (builder, context: Organization[]) =\u003e {\n    for (const org of context) {\n      builder\n        .column(`orga-${org.id}`, {\n          label: `User in ${org.name}`,\n          key: 'organizations',\n          transform: orgs =\u003e orgs.some(o =\u003e o.id === org.id) ? 'YES' : 'NO',\n          cellStyle: data =\u003e ({\n            font: {\n              color: { rgb: data.organizations.some(o =\u003e o.id === org.id) ? '61eb34' : 'd10808' },\n            },\n          }),\n        })\n    }\n  })\n  .build()\n```\n\n#### 3. Safely compose excel file from schemas\n\n```ts\nimport { ExcelBuilder } from '@chronicstone/typed-xlsx'\n\nconst buffer = ExcelBuilder\n  .create()\n  .sheet('Users - full')\n  .addTable({\n    data: users,\n    schema: assessmentExport,\n    context: {\n      'group:org': organizations,\n    },\n  })\n  .sheet('Users - partial')\n  .addTable({\n    data: users,\n    schema: assessmentExport,\n    select: {\n      firstName: true,\n      lastName: true,\n      email: true,\n    },\n  })\n  .sheet('User - neg partial')\n  .addTable({\n    data: users,\n    schema: assessmentExport,\n    select: {\n      firstName: false,\n      lastName: false,\n      email: false,\n    },\n    context: {\n      'group:org': organizations,\n    },\n  })\n  .sheet('User - Multiple tables')\n  .sheet('Multi-tables-grid', { tablesPerRow: 2 })\n  .addTable({\n    title: 'Table 1',\n    data: users.filter((_, i) =\u003e i \u003c 5),\n    schema: assessmentExport,\n    select: { firstName: true, lastName: true, email: true, createdAt: true },\n  })\n  .addTable({\n    title: 'Table 2',\n    data: users.filter((_, i) =\u003e i \u003c 5),\n    schema: assessmentExport,\n    select: { firstName: true, lastName: true, email: true, balance: true },\n  })\n  .addTable({\n    title: 'Table 3',\n    data: users.filter((_, i) =\u003e i \u003c 5),\n    schema: assessmentExport,\n    select: { firstName: true, lastName: true, email: true, balance: true },\n  })\n  .addTable({\n    title: 'Table 4',\n    data: users.filter((_, i) =\u003e i \u003c 5),\n    schema: assessmentExport,\n    select: { firstName: true, lastName: true, email: true, createdAt: true },\n  })\n  .build({ output: 'buffer' })\n\nfs.writeFileSync('test.xlsx', arrayBuffer)\n```\n\n#### 4. Have fun\n\nHere's the generated file for the example from above\n\n[DOWNLOAD GENERATED EXAMPLE](https://github.com/ChronicStone/typed-xlsx/blob/main/example.xlsx)\n\n[OPEN EXAMPLE IN STACKBLITZ](https://stackblitz.com/edit/typescript-cvt29j?file=index.ts)\n\n\n## License\n\n[MIT](./LICENSE) License © 2023-PRESENT [Cyprien THAO](https://github.com/ChronicStone)\n\n\n\u003c!-- Badges --\u003e\n\n[npm-version-src]: https://img.shields.io/npm/v/@chronicstone/typed-xlsx?style=flat\u0026colorA=080f12\u0026colorB=1fa669\n[npm-version-href]: https://npmjs.com/package/@chronicstone/typed-xlsx\n[npm-downloads-src]: https://img.shields.io/npm/dm/@chronicstone/typed-xlsx?style=flat\u0026colorA=080f12\u0026colorB=1fa669\n[npm-downloads-href]: https://npmjs.com/package/@chronicstone/typed-xlsx\n[bundle-src]: https://img.shields.io/bundlephobia/minzip/@chronicstone/typed-xlsx?style=flat\u0026colorA=080f12\u0026colorB=1fa669\u0026label=minzip\n[bundle-href]: https://bundlephobia.com/result?p=@chronicstone/typed-xlsx\n[license-src]: https://img.shields.io/github/license/ChronicStone/typed-xlsx.svg?style=flat\u0026colorA=080f12\u0026colorB=1fa669\n[license-href]: https://github.com/ChronicStone/typed-xlsx/blob/main/LICENSE\n[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat\u0026colorA=080f12\u0026colorB=1fa669\n[jsdocs-href]: https://www.jsdocs.io/package/@chronicstone/typed-xlsx\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChronicStone%2Ftyped-xlsx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FChronicStone%2Ftyped-xlsx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChronicStone%2Ftyped-xlsx/lists"}