Extending TypeScript interface definitions for Airtable automation development environment

I’m setting up a TypeScript development environment for Airtable automations and using rollup to include shared libraries. I’m working with @airtable/blocks package for type definitions.

The issue I’m facing is that I need to extend the Table interface to include a method that doesn’t exist in the original package. Here’s my setup:

// automation.ts  
import { helperFunction } from './shared';
const dataTable = base.getTable('Records');

// Error occurs here - method doesn't exist on Table type
const item = await dataTable.getRecordByIdAsync('rec456', { fields: ['Title'] });
helperFunction(item.getCellValueAsString('Title'));
export {};
// declarations.d.ts
import { type RecordQueryResultOpts } from '@airtable/blocks/dist/types/src/models/record_query_result';
import type TableOrViewQueryResult from '@airtable/blocks/dist/types/src/models/table_or_view_query_result';

declare module '@airtable/blocks' {
  interface Table {
    getRecordByIdAsync(id: string, options?: RecordQueryResultOpts): Promise<TableOrViewQueryResult>;
  }
}

declare global {
  const base: typeof import('@airtable/blocks').base;
  const input: {
    config(): any;
  };
  const output: {
    set(key: string, value: any): void;
  };
}

The TypeScript compiler still throws an error saying the method doesn’t exist on the Table type. How can I properly extend the interface without modifying the source package files?

also, try restarting your ts server after making changes. it can be a bit finicky and need a kick to recognize the new methods you’ve added. good luck!

I ran into something similar when extending third party types. Your approach looks right but the issue is probably module resolution.

Try this instead of importing from the dist path:

// declarations.d.ts
declare module '@airtable/blocks/models' {
  interface Table {
    getRecordByIdAsync(id: string, options?: any): Promise<any>;
  }
}

The key is matching exactly how the original Table interface is exported. Check the actual export structure in the package.

Also make sure your tsconfig includes the declarations file and that it’s in the same directory as your automation.ts or in a parent directory. TypeScript can be picky about where it looks for these extensions.

If that doesn’t work, you might need to create a wrapper function instead of extending the interface directly. Sometimes it’s just easier to work around these type issues than fight them.

The problem is likely that your declarations file isn’t being picked up by TypeScript. Make sure your declarations.d.ts file is included in your tsconfig.json under the include array or typeRoots. Also check that the file path in your module declaration exactly matches how you’re importing the package. I had similar issues when working with custom type extensions and found that sometimes you need to reference the specific submodule path rather than the main package. Try importing directly from the specific model file instead of the root package and see if that resolves the type recognition issue.

One thing that worked for me when dealing with stubborn module augmentation was ensuring the declarations file gets processed before any imports. Move your declarations.d.ts to the root of your project and add a triple-slash reference directive at the top of your automation.ts file: /// <reference path="./declarations.d.ts" />. This forces TypeScript to load your extensions early in the compilation process. Another gotcha I encountered was that the return type needs to match exactly what the method actually returns at runtime. Since you’re extending with a custom method, you might need to implement it as well, not just declare it. Consider creating a utility function that casts the table to your extended type after adding the method to the prototype, which gives you both runtime functionality and compile-time type safety.