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?
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.