【问题标题】:Extend a namespace from package typings从包类型扩展命名空间
【发布时间】:2017-11-24 07:56:48
【问题描述】:

我在这里尝试从包类型扩展命名空间@typings/fullcalendar

/// <reference path="./types/fullcalendar" />

import * as fullcalendar from 'fullcalendar';
import { TimeGrid } from 'fullcalendar';

// TimeGrid and fullcalendar.views are used then

原文打字见here

而 fullcalendar-custom.d.ts 是

import * as FC from 'fullcalendar';

export as namespace FC;

declare class TimeGrid { prepareHits() }

declare let views: any;

这会导致类型错误,因此很明显fullcalendar 命名空间没有正确扩展:

TS2305:模块 '".../node_modules/@types/fullcalendar/index"' 没有导出的成员 'TimeGrid'。

TS2339:类型“typeof”上不存在属性“views”.../node_modules/@types/ 完整日历/索引"'。

这应该如何以正确的方式完成?

考虑到types 目录是在typeRoots 中指定的,这里可以避免reference 指令吗?

该应用程序与 Webpack 和 awesome-typescript-loader 捆绑在一起,因此其行为可能与其他编译方法不同。在某些时候类型在 IDE 检查 (WebStorm) 中似乎没问题,但在编译时仍然出现类型错误。

【问题讨论】:

    标签: typescript typescript2.0


    【解决方案1】:

    我们可以在非声明.ts 中导入命名空间,然后将其再次导出为扩展类型:

    // custom-fc.ts : enhances declaration of FC namespace
    import * as origFC from "fullcalendar";
    
    declare namespace Complimentary {
        class TimeGrid {
            prepareHits(): void;
        }
        let views: any;
    }
    
    // apply additional types to origFc and export again
    export const FC: (typeof Complimentary & typeof origFC) = origFC as any;
    

     

    // use-fc.ts : consumer of extended declaration
    import { FC } from "./custom-fc";
    
    console.log(FC.TimeGrid);
    console.log(FC.views);
    

    (这与您的情况有所不同,因为我使用的是 @types/ 包和 webpack ts-loader,但您应该能够做类似的事情。)

    【讨论】:

    • 谢谢,我尽量避免重新导出,因为我没有在我扩展类型的地方扩展包本身,但它可以完成工作。我最终得到了declare class Complimentary ... export default &lt;typeof origFC &amp; ExtendedFC&gt;&lt;any&gt;origFC; 。命名空间对 TS 来说是可以的,但会导致 IDE 出现一些类型问题。
    • 不能在 TS3 中工作?导出默认 original;不能使用命名空间“原始”作为值。不能将命名空间“扩展”用作类型。
    • 有没有办法在不更改名称的情况下扩展原始命名空间?
    【解决方案2】:

    您可以轻松扩展“fullcalendar”或任何其他 TypeScript 命名空间。

    示例:创建 fullcalendar-extension.d.ts 文件

    /// <reference path="<path-to-typings-dir>/fullcalendar/index.d.ts" />
    
    declare module 'fullcalendar' {
    
      export interface TimeGrid {
    
        customField: string;
    
        customMethod(arg1: number, arg2: boolean): boolean;
    
        prepareHits();
      }
    
      namespace customNamespace {
    
        export interface AnotherTimeGrid {
          customField1: string;
          customField2: boolean;
        }
      }
    }
    

    注意:确保该文件被 TypeScript 编译器拾取。

    使用扩展模块中新定义的类型。

    // one way
    import { TimeGrid } from 'fullcalendar';
    
    const timeGrid: TimeGrid;
    
    // second way
    import * as fc from 'fullcalendar';
    
    const timeGrid: fc.TimeGrid;
    const anotherTimeGrid: fc.customNamespace.AnotherTimeGrid;
    

    有关模块和命名空间的更多信息,您可以查看 ModulesNamespaces 上的 TypeScript 文档并使用它们 together

    干杯!

    【讨论】:

    • 但是customNamespace 应该如何以“一种方式”被识别呢?我正在尝试做import { TimeGrid } from 'fullcalendar'; class CustomGrid extends TimeGrid { ... },但 TimeGrid 及其方法无法从界面中识别(而且我看不到它在“第二种方式”中的工作方式)。
    • 在给定的示例中,TimeGrid 被定义为一个接口,CustomGrid 类只能实现它。如果 TimeGrid 是可以在 fullcalendar 库中扩展的类,则在 fullcalendar-extension.d.ts 文件中将其声明为类。用 'class' 替换 'interface' 关键字很简单。
    • 关于导入,由于ES6模块的对象解构能力有限,'customNamespace'只能按照'第二种方式'使用。
    【解决方案3】:

    使用最新的 TypeScript v4,当我在将外部文件和库与 Svelte 组合时遇到问题时,我这样做了:

    // root/my-declarations.d.ts
    
    import { SomeNameSpace as SomeNameSpaceOriginal} from '../../any-relative-path/to/ts-file';
    import {SvelteComponentDev} from 'svelte/internal';
    
    declare namespace SomeNameSpaceExtended {
        function setValue(value:any):any
        let UI:SvelteComponentDev
        let abc:string
    }
    
    declare global {
        //this will add new items to top-level (root)
        //note: in my case, only importing "as SomeNameSpaceOriginal" gave me correct typing later using our new extended global SomeNameSpace
        let SomeNameSpace: typeof SomeNameSpaceOriginal & typeof SomeNameSpaceExtended;
    
        //this will add new items to window:
        interface Window {
            elementInside:'window.elementInside'
        }
    }
    

    Upvoted Answer 与 https://stackoverflow.com/a/63973683 相结合,最能理解如何扩展事物。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 2014-01-21
      • 2012-01-08
      • 2021-12-02
      相关资源
      最近更新 更多