Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: es6 import type definition (.d.ts) from node_modules subfolder

I have a npm package that has the following type definitions (simplified):

./node_modules/ag-grid-react/main.d.ts

export declare class AgGridReact extends Component<AgGridReactProps, {}> {}

./node_modules/ag-grid-react/lib/agGridReact.d.ts

export declare class AgGridReact extends Component<AgGridReactProps, {}> {
    gridOptions: GridOptions;
    api: GridApi | null;
    columnApi: ColumnApi;
}

I am using the component in my react component like this:

import { AgGridReact } from 'ag-grid-react'

const HelpRequests= () => {
  const grid = useRef<AgGridReact>(null)

  if (grid.current) console.log(grid.current.columnApi)

  return (<AgGridReact ref={grid}/>)
}

The Problem:

Typescript does complain that there is no columnApi. It seems it sadly picks the wrong type from the main.d.ts

I found that I can import the type from the agGridReact.d.ts directly and use it like this:

import {AgGridReact as AgGridReactType} from 'ag-grid-react/lib/agGridReact'

...

const grid = useRef<AgGridReactType>(null)

Question:

Is this the correct way to address this issue? Will typescript be smart enough not to import the ./node_modules/ag-grid-react/lib/agGridReact.ts file which could cause my bundle size to go up?

I've searched a lot but could not find anything about importing types only from node_modules subfolders.

like image 799
pa1nd Avatar asked Jun 13 '26 19:06

pa1nd


1 Answers

I will try to answer this:

Let's assume there is an xyz library and it has these files:

xyz/lib/main.ts:

export const test = 1000

and

xyz/main.ts:

export * from './lib/main.ts'
export const test = 'foo bar'

And I would like to use xyz in my app.ts, and I am aware of only its main.ts file as I think it is the main file which exports everything from library. So I am most likely to do:

app.ts:

import { test } from './xyz/main'

console.debug(test) // it will print 'foo bar'

Now, somebody goes and comment this line in the library:

xyz/main.ts:

export * from './lib/main.ts'
// export const test = 'foo bar'

Now, what will be printed by my app.ts? It will print 1000.


The same thing is happening there with ag-grid-react. It (ag-grid-react/main.d.ts) is overriding the apparently correct (better) class declaration present in ag-grid-react/lib/agGridReact.d.ts. And it is perfectly fine to import from inner path.

main.d.ts:

export * from './lib/agGridReact'; // it is exporting from innner path too
export declare class AgGridColumn extends Component<AgGridColumnProps | AgGridColumnGroupProps, {}> { // and overriding here at the same time
}

agGridReact.d.ts:

export declare class AgGridReact extends Component<AgGridReactProps, {}> {
    props: any;
    state: any;
    static propTypes: any;
    gridOptions: GridOptions;
    changeDetectionService: ChangeDetectionService;
    api: GridApi | null;
    columnApi: ColumnApi;
    portals: ReactPortal[];
    hasPendingPortalUpdate: boolean;
    destroyed: boolean;
    protected eGridDiv: HTMLElement;
    private static MAX_COMPONENT_CREATION_TIME;
    constructor(props: any, state: any);
    render(): React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)>) | (new (props: any) => React.Component<any, any, any>)>;
    createStyleForDiv(): any;
    componentDidMount(): void;
    waitForInstance(reactComponent: ReactComponent, resolve: (value: any) => void, runningTime?: number): void;
    mountReactPortal(portal: ReactPortal, reactComponent: ReactComponent, resolve: (value: any) => void): void;
    batchUpdate(callback?: any): any;
    destroyPortal(portal: ReactPortal): void;
    private getStrategyTypeForProp;
    shouldComponentUpdate(nextProps: any): boolean;
    componentDidUpdate(prevProps: any): void;
    processPropsChanges(prevProps: any, nextProps: any): void;
    private extractDeclarativeColDefChanges;
    private extractGridPropertyChanges;
    componentWillUnmount(): void;
    isDisableStaticMarkup(): boolean;
}

I can't exactly say why ag-grid did this. I found this looking at the typing files. I may be incorrect too.

like image 162
Ajeet Shah Avatar answered Jun 15 '26 22:06

Ajeet Shah