TypeScript:如何从 node_modules 子文件夹导入带类型定义的 ES6 模块(.d.ts)?

3

我有一个npm包,其中包含以下类型定义(简化版):

./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;
}

我将使用以下方式在我的React组件中使用该组件:

我正在我的React组件中使用这个组件:

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}/>)
}

问题:

Typescript报错说没有columnApi。它似乎从main.d.ts中选择了错误的类型。

我发现可以直接从agGridReact.d.ts中导入类型并像这样使用:

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

...

const grid = useRef<AgGridReactType>(null)

问题:

这是解决问题的正确方法吗? TypeScript 是否足够聪明,不会导入 ./node_modules/ag-grid-react/lib/agGridReact.ts 文件,从而导致我的捆绑包大小增加?

我已经搜索了很多内容,但没有找到有关仅从 node_modules 子文件夹中导入类型的任何信息。

1个回答

1
我会尝试回答这个问题:
假设有一个名为xyz的库,它包含以下文件:

xyz/lib/main.ts:

export const test = 1000

并且

xyz/main.ts:

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

我希望在我的app.ts中使用xyz,我只知道它的main.ts文件,因为我认为它是从库中导出所有内容的主要文件。所以我最有可能做的是:

app.ts:

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

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

现在,有人在库中评论了这一行:

xyz/main.ts:

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

现在,我的app.ts会打印出1000
同样的事情也正在发生在ag-grid-react中。它(ag-grid-react/main.d.ts)覆盖了明显正确(更好的)的类声明,该声明存在于ag-grid-react/lib/agGridReact.d.ts中。从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;
}

我无法确切地说明为什么 ag-grid 这样做。我是在查看类型文件时发现的。我也可能是不正确的。


TypeScript会聪明到不会导入./node_modules/ag-grid-react/lib/agGridReact.ts文件,这可能会导致我的捆绑包大小增加吗? - pa1nd
不,TypeScript 不会这样做。当你导入时,TypeScript 只考虑路径和导入的项目,此时它并不关心捆绑包大小。另外,TypeScript 只是为了简化开发工作。最终,在浏览器或服务器上,它只是纯 JS。捆绑包大小取决于你在代码中编写和使用的内容(从库中)。 - Ajeet Shah
@pa1nd 类型仅存在于编译时,因此即使 TypeScript 使用它,也不会导致捆绑包大小增加。 - Slaus
@Slaus 我不担心 .d.ts 文件,而是同名的 .ts 文件!因为我的 import ... from '' 没有指定文件后缀。所以它可能被理解为 .ts(这很可能是对的,对吗?) - pa1nd
1
@pa1nd 不确定,但是,无论如何,如果你有任何构建系统(可能是webpack),它只包括你从主模块调用的函数(类只是构造函数) - 无论你导入哪些文件。因此,我认为不应该担心捆绑增长的原因。 - Slaus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接