TypeScript Support
Jspreadsheet provides comprehensive TypeScript support with built-in type definitions, enabling developers to build type-safe spreadsheet applications. This guide covers TypeScript-specific features, type definitions, and best practices for integrating Jspreadsheet into TypeScript projects.
Documentation
Installation with Types
npm install jspreadsheet
# Types are included in the main package
Type-Safe Spreadsheet Creation
Create spreadsheets with full type safety:
import jspreadsheet, { SpreadsheetConfig, WorksheetInstance } from 'jspreadsheet';
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
const config: SpreadsheetConfig = {
worksheets: [{
data: [
['Product', 'Price', 'Available'],
['Laptop', 999.99, true],
['Mouse', 29.99, false]
],
columns: [
{ type: 'text', title: 'Product Name', width: 200 },
{ type: 'number', title: 'Price ($)', width: 100 },
{ type: 'checkbox', title: 'In Stock', width: 80 }
],
minDimensions: [3, 10]
}]
};
const spreadsheet: WorksheetInstance[] = jspreadsheet(document.getElementById('spreadsheet'), config);
Custom Cell Types with TypeScript
Create type-safe custom cell editors using imported types:
import jspreadsheet, { Editor, worksheetInstance, Column, Cell } from 'jspreadsheet';
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// Create a custom email cell type using the built-in Editor interface
const emailCellType: Editor = {
createCell: (cell: HTMLTableCellElement, value: any, x: number, y: number, instance: worksheetInstance, options: Column | Cell) => {
const input = document.createElement('input');
input.type = 'email';
input.value = value || '';
input.classList.add('jss_input');
input.style.width = '100%';
input.style.border = 'none';
input.style.outline = 'none';
cell.appendChild(input);
input.focus();
},
updateCell: (cell: HTMLTableCellElement, value: any, x: number, y: number, instance: worksheetInstance, options: Column | Cell) => {
const input = cell.querySelector('input') as HTMLInputElement;
if (input) {
input.value = value || '';
}
},
openEditor: (cell: HTMLTableCellElement, value: any, x: number, y: number, instance: worksheetInstance, options: Column | Cell) => {
const input = cell.querySelector('input') as HTMLInputElement;
if (input) {
input.focus();
input.select();
}
},
closeEditor: (cell: HTMLTableCellElement, confirmChanges: boolean, x: number, y: number, instance: worksheetInstance, options: Column | Cell) => {
const input = cell.querySelector('input') as HTMLInputElement;
if (input && confirmChanges) {
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const isValid = emailRegex.test(input.value);
if (!isValid && input.value.trim() !== '') {
alert('Please enter a valid email address');
return false; // Prevent saving invalid email
}
return input.value;
}
return '';
},
destroyCell: (cell: HTMLTableCellElement, x: number, y: number, instance: worksheetInstance) => {
// Cleanup when cell is destroyed
const input = cell.querySelector('input');
if (input) {
input.remove();
}
}
};
// Use the custom editor in a spreadsheet configuration
const config = {
worksheets: [{
data: [
['Name', 'Email'],
['John Doe', '[email protected]'],
['Jane Smith', '[email protected]']
],
columns: [
{ type: 'text', title: 'Full Name', width: 200 },
{ type: emailCellType, title: 'Email Address', width: 250 }
]
}]
};
const spreadsheet = jspreadsheet(document.getElementById('spreadsheet'), config);
Event Handling with TypeScript
Type-safe event handlers using imported types:
import jspreadsheet, { WorksheetInstance, SpreadsheetConfig } from 'jspreadsheet';
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// Use the built-in event handler types from Jspreadsheet
const config: SpreadsheetConfig = {
worksheets: [{
data: [
['Name', 'Age', 'City'],
['John', 30, 'New York'],
['Jane', 25, 'London']
],
onchange: (worksheet: WorksheetInstance, cell: HTMLElement, x: number, y: number, value: any, oldValue: any) => {
console.log(`Cell ${worksheet.getCellNameFromCoords(x, y)} changed from '${oldValue}' to '${value}'`);
},
onselection: (worksheet: WorksheetInstance, x1: number, y1: number, x2: number, y2: number) => {
const range = worksheet.getRangeFromCoords(x1, y1, x2, y2);
console.log(`Selected range: ${range}`);
},
onbeforechange: (worksheet: WorksheetInstance, cell: HTMLElement, x: number, y: number, value: any) => {
// Type-safe validation
if (typeof value === 'string' && value.length > 100) {
alert('Text too long!');
return false; // Prevent change
}
return value;
}
}]
};
// Create spreadsheet with type-safe event handlers
const spreadsheet: WorksheetInstance[] = jspreadsheet(document.getElementById('spreadsheet'), config);
Complete Type Definitions
For developers who want to explore all available interfaces and types, you can view the complete TypeScript definitions:
📄 View Complete Type Definitions
Framework Integration
React Application with File Loading
Complete React application example with TypeScript, demonstrating file loading, validations, and proper typing:
import React, { useRef } from "react";
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/react";
import formula from "@jspreadsheet/formula-pro";
import parser from "@jspreadsheet/parser";
import render from "@jspreadsheet/render";
// Style dependencies
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// Load the extensions
jspreadsheet.setExtensions({ formula, parser, render });
export default function App() {
// Properly type the spreadsheet ref
const spreadsheet = useRef<jspreadsheet.worksheetInstance[]>();
// Input ref for file loading
const inputRef = useRef<HTMLInputElement>(null);
// Get the root element
const getRootElement = function() {
if (spreadsheet.current) {
return spreadsheet.current[0].parent.element;
}
}
// Create the spreadsheet from a local file
const load = function (e: React.ChangeEvent<HTMLInputElement>) {
// Parse XLSX file and create a new spreadsheet
if (jspreadsheet.parser && e.target.files) {
jspreadsheet.parser({
file: e.target.files[0],
locale: "en-GB",
onload: function (config) {
let root = getRootElement();
if (root) {
// Destroy the existing one first
jspreadsheet.destroy(root);
// Create a new spreadsheet from the file
jspreadsheet(root, config);
}
},
onerror: function (error) {
alert(error);
},
});
}
}
// Custom event to remove all strings that start with #
const afterChanges = function(worksheet: jspreadsheet.worksheetInstance, records: jspreadsheet.Record[]) {
for (let i = 0; i < records.length; i++) {
let x = records[i].x;
let y = records[i].y;
let record = worksheet.getCellObject(x, y);
if (record.element && typeof(record.v) === 'string' && record.v.startsWith('#')) {
// Clear what users see on the cell
record.element.textContent = '';
}
}
}
// Custom event to show all worksheets
const onload = function(spreadsheet: jspreadsheet.spreadsheetInstance) {
for (let i = 0; i < spreadsheet.worksheets.length; i++) {
spreadsheet.worksheets[i].openWorksheet();
spreadsheet.worksheets[i].element.style.display = 'block';
}
}
// Type-safe style configuration
const style: string[] = [
'background: yellow'
]
// Type-safe column configuration
const columns: jspreadsheet.Column[] = [
{ type: 'numeric' },
{ type: 'text' },
{},
{ s: 0, mask: '@' },
]
// Type-safe validation rules
const validations: jspreadsheet.Validation[] = [
{
range: 'Sheet1!A1:A3',
action: "warning",
criteria: "<",
type: "number",
value: [500],
text: 'Custom message about the number',
},
{
range: 'Sheet1!B1:B3',
action: "format",
criteria: "<",
type: "number",
value: [75],
format: { 'background-color': 'red' },
},
{
range: 'Sheet1!B1:B3',
action: "format",
criteria: "<",
type: "number",
value: [50],
format: { 'background-color': 'orange' },
},
{
range: 'Sheet1!B1:B3',
action: "format",
criteria: "<",
type: "number",
value: [25],
format: { 'background-color': 'green' },
}
]
const data = [
['007', '007', '007', '007'],
['', '49', ''],
['', '69', ''],
]
return (
<div>
<Spreadsheet
ref={spreadsheet}
tabs={true}
style={style}
onload={onload}
onafterchanges={afterChanges}
validations={validations}
>
<Worksheet minDimensions={[4, 4]} columns={columns} data={data} />
<Worksheet minDimensions={[4, 4]} columns={columns} />
</Spreadsheet>
<input
ref={inputRef}
id="file"
type="file"
name="file"
onChange={load}
style={{ display: "none" }}
/>
<p>
<input
type="button"
value="Load a XLSX file from my local computer"
onClick={() => inputRef.current!.click()}
/>
</p>
</div>
);
}
More Examples
You can use TypeScript with Jspreadsheet in any of your favorite frameworks:
- React Spreadsheet - Type-safe React components and hooks
- Angular Spreadsheet - Angular services and dependency injection
- Vue Data Grid - Vue 3 Composition API with TypeScript