How to refer to Typescript enum in d.ts file, when using AMD?

Stephan G picture Stephan G · Jul 12, 2016 · Viewed 16k times · Source

I want to define a typescript interface to represent, say, an error. Something like this:

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

interface IMyMessage {
    name: string;
    level: MessageLevel;
    message: string;
}

This works fine as far as it goes. However, now (perhaps) I want to declare that interface in a .d.ts file so others can use it for typing. But I don't want to define the enum in the .d.ts file, since that would be implementation and not simple typing information. The enum should presumably be in a .ts file, let's call it messageLevel.ts:

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

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

and I can, at this point, use it in my d.ts typing file this way:

import * as ml from "./MessageLevel";

interface IMyMessage {
    name: string;
    level: ml.MessageLevel;
    message: string;
}

and I can make this work, but I don't like the level-mixing of importing an implementation file into a typing file. Nor do I like the idea of actually implementing an enum in a typings file.

Is there a clean way to do this that keeps implementation and declaration strictly separate?

Answer

Katana314 picture Katana314 · Jul 14, 2016

The best solution may depend on whether you have a preference for the actual JavaScript variable being a number, a string, or otherwise. If you don't mind String, you can do it like this:

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

So in the end JavaScript, it will simply be represented as a string, but TypeScript will flag an error anytime you compare it to a value not in that list, or try to assign it to a different string. Since this is the closest that JavaScript itself has to any kind of enum (eg, document.createElement("video") rather than document.createElement(ElementTypes.VIDEO), it might be one of the better ways of expressing this logic.