Skip to content

satocchi0416sh/typed-notion

Repository files navigation

typed-notion-core-ts

npm version TypeScript License: MIT

Type-safe Notion API library with compile-time validation and runtime type inference.

Key Features

  • Type Safety First: End-to-end type safety from schema definition to API response
  • Complex Properties: Full type inference for Rollups and Formulas using helper functions
  • Zero Dependencies: Lightweight (7.75KB gzipped) and ideal for edge environments
  • Runtime Validation: Protects your application from silent schema changes in Notion

Installation

npm install typed-notion-core-ts

Quick Start

The core philosophy is "Schema First". Define your schema, and get types for free.

import { createTypedSchema, NotionClient, rollup, formula } from 'typed-notion-core-ts';

// 1. Define your Notion database schema
const projectSchema = createTypedSchema({
  title: { type: 'title' },
  status: {
    type: 'select',
    options: ['Planning', 'In Progress', 'Done'],
  },
  // ✨ Automatic type inference for complex properties
  taskCount: rollup('Tasks', 'Name', 'count'), // -> number | null
  isOverdue: formula('boolean', 'prop("Due") < now()'), // -> boolean | null
});

// 2. Initialize the client
const client = new NotionClient({ auth: process.env.NOTION_TOKEN });

// 3. Type-safe database operations
const newProject = await client.create(projectSchema, {
  title: 'Website Redesign',
  status: 'Planning', // ✅ Auto-completed & Validated
  // taskCount and isOverdue are read-only, excluded from creation
});

// 4. Type-safe response
const project = await client.getPage(projectSchema, newProject.id);
if (project.isOverdue) {
  console.log(`Warning: ${project.title} has ${project.taskCount} tasks!`);
}

Core Concepts

Schema Definition

Define your database structure once, use it everywhere with full type safety:

import { createTypedSchema, formula, rollup } from 'typed-notion-core-ts';

const schema = createTypedSchema({
  // Basic properties
  title: { type: 'title' },
  completed: { type: 'checkbox' },
  priority: {
    type: 'select',
    options: ['Low', 'Medium', 'High', 'Urgent'],
  },
  tags: {
    type: 'multi_select',
    options: ['Frontend', 'Backend', 'Design', 'Bug'],
  },
  assignee: { type: 'people' },
  dueDate: { type: 'date' },

  // Complex properties with type inference
  totalBudget: rollup('Expenses', 'Amount', 'sum'), // -> number | null
  lastUpdate: rollup('Activity', 'Date', 'latest'), // -> Date | null
  progress: formula('number', 'prop("Completed") / prop("Total") * 100'),
  statusLabel: formula('string', 'concat("Task: ", prop("Title"))'),
});

Type Inference

Export TypeScript types directly from your runtime schema:

import { InferSchemaProperties } from 'typed-notion-core-ts';

// Automatically inferred from schema
type Project = InferSchemaProperties<typeof projectSchema>;

function processProject(project: Project) {
  // TypeScript knows exact types
  if (project.status === 'Done') {
    // ✅ 'Planning' | 'In Progress' | 'Done'
    console.log(project.taskCount); // ✅ number | null
    console.log(project.title); // ✅ string
  }
}

Database Operations

Query with Filters

const activeProjects = await client.query(projectSchema, {
  filter: {
    and: [
      { property: 'status', select: { equals: 'In Progress' } },
      { property: 'taskCount', number: { greater_than: 0 } },
    ],
  },
  sorts: [{ property: 'dueDate', direction: 'ascending' }],
});

// Type-safe iteration
activeProjects.results.forEach(project => {
  // project is fully typed based on schema
  console.log(`${project.title}: ${project.taskCount} tasks`);
});

Create and Update

// Create - only writable properties allowed
const task = await client.create(taskSchema, {
  title: 'Implement authentication',
  priority: 'High',
  tags: ['Backend', 'Security'],
  assignee: [{ id: 'user-id' }],
});

// Update - partial updates supported
await client.update(task.id, taskSchema, {
  completed: true,
  tags: ['Backend', 'Security', 'Done'],
});

Pagination

let allProjects = [];
let hasMore = true;
let cursor = undefined;

while (hasMore) {
  const response = await client.query(projectSchema, {
    page_size: 100,
    start_cursor: cursor,
  });

  allProjects.push(...response.results);
  hasMore = response.has_more;
  cursor = response.next_cursor;
}

Advanced Features

Complex Property Helpers

Helper functions provide ergonomic API for defining complex properties:

import { rollup, formula, union } from 'typed-notion-core-ts';

const advancedSchema = createTypedSchema({
  // Rollup with automatic type inference
  totalSpent: rollup('Transactions', 'Amount', 'sum'),
  earliestTask: rollup('Tasks', 'Created', 'earliest'),

  // Formula with explicit type hints
  isUrgent: formula('boolean'),
  displayName: formula('string'),
  score: formula('number'),

  // Union types for conditional formulas
  dynamicValue: formula(union('string', 'number'), 'if(prop("IsText"), "Text Value", 42)'), // -> string | number | null
});

Schema Validation

Validate that your local schema matches the actual Notion database:

const validation = await client.validateSchema(projectSchema);

if (!validation.isValid) {
  console.error('Schema mismatch detected:');
  validation.errors.forEach(error => {
    console.error(`- ${error.property}: ${error.message}`);
  });
}

Performance Monitoring

Built-in performance tracking for optimization:

const metrics = client.getPerformanceMetrics();
console.log(`Average response time: ${metrics.averageResponseTime}ms`);
console.log(`Cache hit rate: ${metrics.cacheHitRate}%`);

// Clear cache when needed
client.clearCaches();

Configuration Management

import { DatabaseConfigManager } from 'typed-notion-core-ts';

const config = new DatabaseConfigManager();

// Set database IDs from environment
config.setDatabaseId('projects', process.env.PROJECTS_DB_ID);
config.setDatabaseId('tasks', process.env.TASKS_DB_ID);

// Auto-resolve database IDs
const projects = await client.query(projectSchema); // Uses configured ID

Supported Property Types

Type inference covers 100% of Notion property types. There is no implicit any.

Property Type TypeScript Type Validation / Inference
title string Required, non-empty
rich_text string Text content (plain text)
number number Numeric values
select string (Union) Matches defined options exactly
multi_select string[] (Union) Array of defined options
date Date | string ISO date format support
checkbox boolean True / False
people NotionUser[] Notion user objects
files File[] File objects
url string Valid URL format
email string Valid email format
phone_number string Phone number format
relation string[] Array of Page IDs
formula T | null Inferred from Developer Hint (String, Number, Boolean, Date, Union)
rollup T | null Auto-inferred from Source (Matches source property type)

Note on Nullability: Unlike standard Notion API responses, this library treats rollup and formula results as nullable (| null) by default. This forces you to handle cases where calculation fails or data is missing, preventing runtime crashes.

API Reference

Schema Creation

  • createTypedSchema(definition) - Create a typed schema from property definitions
  • rollup(relation, property, function) - Define a rollup property with type inference
  • formula(returnType, expression?) - Define a formula with explicit type hint
  • union(...types) - Create union type for complex formulas

Client Operations

  • new NotionClient(config) - Initialize Notion client with authentication
  • client.query(schema, options?) - Query database with filters and sorting
  • client.create(schema, data) - Create new database entry
  • client.update(id, schema, data) - Update existing entry
  • client.getPage(schema, id) - Retrieve single page by ID
  • client.validateSchema(schema) - Validate schema against database

Type Utilities

  • InferSchemaProperties<T> - Extract TypeScript type from schema
  • PropertyType - Union of all supported Notion property types
  • SchemaDefinition - Type for schema configuration object

Contributing

We welcome contributions! Please see CONTRIBUTING.md for development setup, testing guidelines, and submission process.

License

MIT © Satoyoshi

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •