Додавання функцій до Enum


81

Чи можна додати функції до типу 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може бути дивним, просто цікаво, чи можливо це.

Відповіді:


103

Ви можете мати клас, який відокремлений від Enum, і використовувати його для отримання потрібних речей, або можна об’єднати простір імен у Enum і отримати все те, що схоже на те саме місце.

Клас корисності режиму

Отже, це не зовсім те, за чим ви переслідуєте, але це дозволяє інкапсулювати поведінку "Режим у рядок", використовуючи статичний метод.

class ModeUtil {
    public static toString(mode: Mode) {
        return Mode[mode];
    }
}

Ви можете використовувати його так:

const mode = Mode.portrait;
const x = ModeUtil.toString(mode);
console.log(x);

Режим Enum / Простір імен Злиття

Ви можете об’єднати простір імен з Enum, щоб створити те, що схоже на Enum, за допомогою додаткових методів:

enum Mode {
    X,
    Y
}

namespace Mode {
    export function toString(mode: Mode): string {
        return Mode[mode];
    }

    export function parse(mode: string): Mode {
        return Mode[mode];
    }
}

const mode = Mode.X;

const str = Mode.toString(mode);
alert(str);

const m = Mode.parse(str);
alert(m);

4
Чи є спосіб додати метод до члена переліку?
Jay Wick

Будь-які переваги використання модуля перед класом?
Даніель

2
@Daniel - Я оновив відповідь, як moduleзараз namespace. Я також підкреслив ключову перевагу простору імен у цьому конкретному випадку, тобто методи, що відображаються під переліком, тобто Mode.
Фентон,

@Fenton - я б хотів import { Mode } from "./Mode.ts"і використовував його так само, як у вашому прикладі використання - чи можливо це з об’єднаними просторами імен?
Ведран

2
Варто зазначити, що namespaceпідхід потенційно може спричинити проблеми в тому, що функції, які споживають "перерахування" (наприклад, щоб повторити члени перерахування для заповнення вибраного списку), дадуть несподівані результати, такі як "myAddedMethod () {...}". Ви можете відфільтрувати сторонніх членів, що не є переліченими, у точці ітерації, але лише зазначивши, що цей підхід не позбавлений недоліків.
virtualeyes

30

Ви можете отримати значення рядка неперервного переліку, використовуючи квадратні дужки:

class Device {
    constructor(public mode:Mode) {
        console.log(Mode[this.mode]);
    }
}

Ви також можете додати до переліку деякі утиліти, специфічні для переліку, але це точно так само, як статичні члени класу:

enum Mode {
    landscape,
    portrait
}

namespace Mode {
    export function doSomething(mode:Mode) {
        // your code here
    }
}

1
import Mode = require('Mode'); ... /*more code here...*/ <Mode.landscape> landScape = Mode.landscape;і я отримав помилку: error TS2503: Cannot find namespace 'Mode'
pawciobiel

1
@pawciobiel Ну, я думаю, Modeце тип, до якого ви хочете перейти, а ні landscape. Змініть свій склад <Mode.landscape>на просто<Mode>
Бенджамін

просто зауважимо, що це не працює в TS 1.8.10. мені довелося додати exportперед визначенням модуля.
icfantv

@icfantv Працює без змін на typescriptlang.org/play (додаючи рядок Mode.doSomething(Mode.landscape);в кінці для тестування)
Бенджамін

1
Я думаю, що це було тому, що мій перелік також мав, exportі проблема полягає в тому, що для того, щоб TS об'єднав два об'єкти, їх потрібно або експортувати, або обох не бути. Вибачте за непорозуміння.
icfantv

15

Перетворіть свою 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;
   }
}

1
Ваш власний приклад можна розглядати як контраргумент вашій думці. Висота / ширина часто змінюються залежно від інших речей, не тільки "пейзаж проти портрета" - вони не належать до цього переліку. Цей перелік справді виражає лише туманні переваги, його точне значення залежить від контексту.
Всеволод Голованов

1
@VsevolodGolovanov впевнений, це лише приклад, який демонструє, як це налаштувати. Я не пропоную використовувати Modeперелік із цими значеннями. використовуйте будь-які значення, що стосуються вашого проекту.
Dave Cousineau

Думаю, що говорить @VsevolodGolovanov, це те, що об’єкт значення (як ви запропонували) не є перерахуванням і що незалежно від того, які значення ви використовуєте, вони насправді не належатимуть до переліку.
Крістіан

1
@Christian він говорив, що "ширина", "висота" та "співвідношення сторін" насправді не є властивостями "пейзажу" та "портрета"; тобто: поняття ландшафту не залежить від розміру. це правда, але це лише приклад.
Dave Cousineau

2

може зробити перелічення як приватний конструктор та статичний об'єкт повернення get

export class HomeSlideEnum{

  public static get friendList(): HomeSlideEnum {

    return new HomeSlideEnum(0, "friendList");

  }
  public static getByOrdinal(ordinal){
    switch(ordinal){
      case 0:

        return HomeSlideEnum.friendList;
    }
  }

  public ordinal:number;
  public key:string;
  private constructor(ordinal, key){

    this.ordinal = ordinal;
    this.key = key;
  }


  public getTitle(){
    switch(this.ordinal){
      case 0:

        return "Friend List"
      default :
        return "DChat"
    }
  }

}

то пізніше можна використовувати ось так

HomeSlideEnum.friendList.getTitle();

2

Додаток до розчину Фентона. Якщо ви хочете використовувати цей перечислювач в іншому класі, вам потрібно експортувати як перелічення, так і простір імен. Це виглядало б так:

export enum Mode {
    landscape,
    portrait
}

export namespace Mode {
    export function toString(mode: Mode): string {
        return Mode[mode];
    }
}

Потім ви просто імпортуєте файл mode.enum.ts у свій клас і використовуєте його.


1
Дякую, я це шукав.
Йорен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.