TypeScript: Добавить функции в Enum
Можно ли добавить функции в тип Enum в TypeScript?
например:
enum Mode {
landscape,
portrait,
// the dream...
toString() { console.log(this); }
}
Или:
class ModeExtension {
public toString = () => console.log(this);
}
enum Mode extends ModeExtension {
landscape,
portrait,
}
Конечно, функция toString()
содержала бы что-то вроде switch
. Но прецедент бы шел по строкам:
class Device {
constructor(public mode:Mode) {
console.log(this.mode.toString());
}
}
Я понимаю, почему расширение enum
может быть странным, просто интересно, возможно ли это.
Ответы
Ответ 1
Во время выполнения var mode = Mode.portrait;
переменная mode
является числом. Вам нужно будет переопределить number.toString
, чтобы получить нужное поведение, и это повлияет на все числа (и все перечисления), что определенно не то, что вы хотите.
Итак, это не совсем то, что вам нужно, но это позволяет вам инкапсулировать поведение "Режим в строку", используя статический метод либо в отдельном классе, либо с помощью объединения enum/module:
class ModeUtil {
public static toString(mode: Mode) {
return Mode[mode];
}
}
Вы можете использовать его следующим образом:
var mode = Mode.portrait;
var x = ModeUtil.toString(mode);
console.log(x);
или
module Mode {
export function toString(mode: Mode) {
return Mode[mode];
}
export function parse(mode: string) {
return Mode[mode];
}
}
Вы можете использовать это:
var mode = Mode.portrait;
var x = Mode.toString(mode);
console.log(x);
И я включил там бонус parse
, который вы можете использовать следующим образом:
var y = Mode.parse('portrait');
console.log(y);
Подробнее о слиянии объявлений (и, в частности, о слиянии модулей с классами, функциями и перечислениями) здесь.
Ответ 2
Вы можете получить строковое значение неконстантного перечисления с помощью квадратных скобок:
class Device {
constructor(public mode:Mode) {
console.log(Mode[this.mode]);
}
}
Вы также можете поместить некоторые enum-специфичные функции использования в перечисление, но это так же, как и статические члены класса:
enum Mode {
landscape,
portrait
}
namespace Mode {
export function doSomething(mode:Mode) {
// your code here
}
}
Ответ 3
Преобразуйте enum
в шаблон перечисления. Я считаю, что это более эффективная практика в целом для многих языков, поскольку в противном случае вы ограничиваете параметры инкапсуляции для своего типа. Тенденция к switch
по значению перечисления, когда действительно любые данные или функциональные возможности, зависящие от конкретного значения перечисления, должны просто входить в каждый экземпляр перечисления. Я добавил еще несколько примеров для демонстрации.
Это может не сработать, если вы особенно зависите от базовых значений перечисления. В этом случае вам нужно будет добавить элемент для старых значений и преобразовать места, в которых он нуждается, чтобы использовать новое свойство.
class Mode {
public static landscape = new Mode(1920, 1080);
public static portrait = new Mode(1080, 1920);
public get Width(): number { return this.mWidth; }
public get Height(): number { return this.mHeight; }
// private constructor if possible in a future version of TS
constructor(
private mWidth: number,
private mHeight: number
) {
}
public GetAspectRatio() {
return this.mWidth / this.mHeight;
}
}