在使用AMD时,如何在d.ts文件中引用Typescript枚举?

Ste*_*n G 11 amd typescript

我想定义一个typescript接口来表示一个错误.像这样的东西:

enum MessageLevel {
    Unknown,
    Fatal,
    Critical,
    Error,
    Warning,
    Info,
    Debug
}

interface IMyMessage {
    name: string;
    level: MessageLevel;
    message: string;
}
Run Code Online (Sandbox Code Playgroud)

这样可以正常工作.但是,现在(也许)我想在.d.ts文件中声明该接口,以便其他人可以使用它进行输入.但我不想在.d.ts文件中定义枚举,因为那将是实现而不是简单的输入信息.枚举应该在.ts文件中,我们称之为messageLevel.ts:

///<amd-module name='MessageLevel'/>

export enum MessageLevel {
    Unknown,
    Fatal,
    Critical,
    Error,
    Warning,
    Info,
    Debug
}
Run Code Online (Sandbox Code Playgroud)

此时我可以通过这种方式在我的d.ts打字文件中使用它:

import * as ml from "./MessageLevel";

interface IMyMessage {
    name: string;
    level: ml.MessageLevel;
    message: string;
}
Run Code Online (Sandbox Code Playgroud)

我可以使这项工作,但我不喜欢将实现文件导入打字文件的级别混合.我也不喜欢在打字文件中实际实现枚举的想法.

是否有一种干净的方法来保持实施和声明严格分开?

Kat*_*314 9

最佳解决方案可能取决于您是否偏好实际的JavaScript变量是数字,字符串或其他.如果你不介意String,你可以这样做:

///messagelevel.d.ts
export type MessageLevel = "Unknown" | "Fatal" | "Critical" | "Error";



///main.d.ts
import * as ml from "./MessageLevel";

interface IMyMessage {
    name: string;
    level: ml.MessageLevel;
    message: string;
}
Run Code Online (Sandbox Code Playgroud)

因此,在最后的JavaScript中,它将简单地表示为字符串,但只要将TypeI与不在该列表中的值进行比较,TypeScript就会标记错误,或者尝试将其分配给不同的字符串.由于这是最接近的JavaScript本身具有任何枚举(以下EG,document.createElement("video")而不是document.createElement(ElementTypes.VIDEO),它可能是表达这种逻辑的较好方式之一.


Flá*_*bôa 7

最近几天,我一直在考虑这个问题,也许const enum,加上工会类型可能是一个合适的选择。

此方法取决于您的API客户端可以期望一些在API文件中明确声明的枚举的事实。

考虑一下。首先,API文件api.d.ts

/**
 * @file api.d.ts
 * 
 * Here you define your public interface, to be
 * implemented by one or more modules.
 */


/**
 * An example enum.
 *  
 * The enum here is `const` so that any reference to its
 * elements are inlined, thereby guaranteeing that none of
 * its members are computed, and that no corresponding 
 * JavaScript code is emmitted by the compiler for this
 * type definition file.
 * 
 * Note how this enum is named distinctly from its
 * "conceptual" implementation, `MyEnum`.
 * TypeScript only allows namespace merging for enums
 * in the case where all namespaces are declared in the
 * same file. Because of that, we cannot augment an enum's
 * namespace across different source files (including
 * `.d.ts` files).
 */
export const enum IMyEnum { A }

/**
 * An example interface.
 */
export interface MyInterface {

    /**
     * An example method.
     * 
     * The method itself receives `IMyEnum` only. Unfortunately,
     * there's no way I'm aware of that would allow a forward
     * declaration of `MyEnum`, like one would do in e.g. C++
     * (e.g. declaration vs definition, ODR).
     */
    myMethod(option: IMyEnum): void;
}
Run Code Online (Sandbox Code Playgroud)

还有一个API实现impl.ts

/**
 * @file impl.ts
 */

/**
 * A runtime "conceptual" implementation for `IMyEnum`.
 */
enum MyEnum {
    // We need to redeclare every member of `IMyEnum`
    // in `MyEnum`, so that the values for each equally named
    // element in both enums are the same.
    // TypeScript will emit something that is accessible at
    // runtime, for example:
    //
    //    MyEnum[MyEnum["A"] = 100] = "A";
    //
    A = IMyEnum.A
}

class MyObject implements IMyInterface {

    // Notice how this union-typed argument still matches its
    // counterpart in `IMyInterface.myMethod`.
    myMethod(option: MyEnum | IMyEnum): void {
        console.log("You selected: " + MyEnum[option]);
    }
}

// ----

var o = new MyObject();
o.myMethod(MyEnum.A);  // ==> You selected: 100
o.myMethod(IMyEnum.A); // ==> You selected: 100

// YAY! (But all this work shouldn't really be necessary, if TypeScript
// was a bit more reasonable regarding enums and type declaration files...)
Run Code Online (Sandbox Code Playgroud)

我以这个要点为例,以防万一有人希望看到这种方法的实际效果。


Dam*_*rev 6

差不多两年过去了,这个问题依然存在。我找不到好的解决方案,因此我创建了一个解决方法,它只告诉您的界面 var 的类型是枚举,而不是哪个枚举。主类有一个“中间件”抽象包装器,它具体将 var 类型设置为所需的枚举。

// globals.d.ts

type EnumType = { [s: any]: any }

interface IMyMessage {
  level: EnumType
}
Run Code Online (Sandbox Code Playgroud)
// enums.ts

export enum MessageLevel {
    Unknown,
    Fatal,
    Critical,
    Error,
    Warning,
    Info,
    Debug
}
Run Code Online (Sandbox Code Playgroud)
// MyClass.ts

import { MessageLevel } from 'enums'

// If your MyMessage class is extending something, MyMessageWrapper has to 
//  extend it instead!
abstract class MyMessageWrapper extends X implements IMyMessage {
  abstract level: MessageLevel
}

class MyMessage extends MyMessageWrapper {
  level = MessageLevel.Unknown // works
  // level = MyOtherEnum.Unknown // doesn't work
}
Run Code Online (Sandbox Code Playgroud)

在某些用例中可能有用。