Единственный способ обойти это - объявить перечисление по-другому.
Один из способов сделать это довольно многословен, но действует во многом как объявленное перечисление с неизвестными значениями.Истинные перечисления в TypeScript добавляют множество именованных типов и значений с небольшим объемом кода, поэтому для имитации этого вручную нам нужно много строк.Общий метод состоит в том, чтобы объявить значение и тип для каждого из A
, A.B
, A.C
и A.D
и сделать это таким образом, чтобы обрабатывать типы каждого значения перечисления как разныедруг от друга, не зная, что они на самом деле:
declare namespace A {
interface _B { readonly __nominal: unique symbol; }
export type B = _B & number;
export const B: B;
interface _C { readonly __nominal: unique symbol; }
export type C = _C & number;
export const C: C;
interface _D { readonly __nominal: unique symbol; }
export type D = _D & number;
export const D: D;
}
type A = A.B | A.C | A.D;
В вышеприведенном, { readonly __nominal: unique symbol }
служит техникой брендинга с использованием уникальных символов для создания TypeScriptобрабатывать каждый из A.B
, A.C
и A.D
как номинально типизированных и, следовательно, отличающихся друг от друга типов, несмотря на то, что они имеют «одинаковую» структуру.Это немного обманывает компилятор, поскольку очевидно, что во время выполнения A.C
не будет иметь свойства с именем __nominal
, но, пока вы его игнорируете, оно должно работать нормально.
Давайте удостоверимся: еслиу вас есть переменная полного типа enum, вы можете назначить ей любой член:
let a: A = A.B; // okay
a = A.C; // okay
a = A.D; // okay
Но если у вас есть переменная только одного из типов членов, вы не можете назначить другие:
let b: A.B = A.B; // specifically only A.B
b = A.C; // error! A.C not assignable to A.B
b = A.D; // error! A.D not assignable to A.B
Теперь разрешены ваши типы:
interface ISomeRestrictedProps {
restrictedProp: A.B | A.C;
}
И ведут себя более или менее так, как вы хотите:
const i: ISomeRestrictedProps = {
restrictedProp: A.B // okay
};
i.restrictedProp = A.C; // okay
i.restrictedProp = A.D; // error! D not assignable to B | C
Ссылка на фирменный перечислимый код
Аналогично, вы можете просто сделать то, что @ TitianCernicova-Dragomir предложило и присвоить значения перечислениям.Они не обязательно должны быть фактическими значениями, если они отличаются друг от друга, и вы не ошибаетесь, считая их действительными значениями:
declare enum A {
B = 0xbbbbb, // dummy value for B
C = 0xccccc, // dummy value for C
D = 0xddddd // dummy value for D
}
Опять вы лжете компилятору о точных значениях, но пока вы просто игнорируете точные значения и не пишете код, который заботится о точных значениях, все должно быть хорошо.Последующий код должен работать так, как вы ожидаете (и я не собираюсь повторять приведенный выше код ... вы можете увидеть, как он работает по следующей ссылке)
Ссылка на dummy-val-enum code
В обоих из них вы немного лжете компилятору ... первый метод многословен, но не притворяется, что вы знаете числовые значения перечисления, тогда какпоследний метод более прост, но, возможно, подвергает риску неосторожного разработчика, который думает, что фиктивные значения являются действительными значениями.
В любом случае, надеюсь, это поможет;удачи!