从包类型扩展命名空间
Posted
技术标签:
【中文标题】从包类型扩展命名空间【英文标题】: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) 中似乎没问题,但在编译时仍然出现类型错误。
【问题讨论】:
【参考方案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 <typeof origFC & ExtendedFC><any>origFC;
。命名空间对 TS 来说是可以的,但会导致 IDE 出现一些类型问题。
不能在 TS3 中工作?导出默认 您可以轻松扩展“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;
有关模块和命名空间的更多信息,您可以查看 Modules 和 Namespaces 上的 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://***.com/a/63973683 相结合,最能理解如何扩展事物。
【讨论】:
以上是关于从包类型扩展命名空间的主要内容,如果未能解决你的问题,请参考以下文章
命名空间“System.Configuration”中不存在类型或命名空间名称“ConfigurationManager”