0

I am trying to use TypeScript to describe the interface for an object. Faced such a problem: How to set an opportunity with help of an interface, limited values ​​in an array. Example:

export interface IChannel {
  title: string
  name: string,
  signal: ["discrete", "analog", "text"] | ["discrete", "analog"] | ["discrete"] | ["analog"] | ["text"] | ["analog", "text"], // OMG... IT"S BAD !!!
  enabled: boolean
  "description": string,
  "isChangeVisibility": boolean
}

Need filed signal = ["discrete" OR/AND "analog" OR/AND "text"] This field must contain only these values. Array length (may be 1, 2 or 3 elements) Thanks for any help. I will sit experimenting.

Vad0k
  • 325
  • 3
  • 13

2 Answers2

3

Using an enum like @axiac suggested is one solution, but then if you want to create an object of type IChannel you have to use the enum values (e.g. you can't do signal: ['discrete'], it has to be signal: [SignalType.discrete] or signal: ['discrete'] as SignalType[]).

IMO an union of literal types is simpler and does not produce any additional JavaScript output (enums are compiled to objects):

type SignalType = 'discrete' | 'analog' | 'text';

export interface IChannel {
  title: string;
  name: string;
  signal: SignalType[];
  enabled: boolean;
  description: string;
  isChangeVisibility: boolean;
}

The downside is that something like ['discrete', 'discrete'] will be okay for the compiler. If it's important to enforce uniqueness of values then your current solution is the only reasonable one I think.

You could also do signal: [SignalType, SignalType?, SignalType?], which enforces the number of elements to 1, 2 or 3 (but still doesn't solve the issue with value uniqueness).

paolostyle
  • 1,849
  • 14
  • 17
  • Thank you @paolostyle. This works well. At the expense of uniqueness is not critical. It is ideal for a compiler. – Vad0k May 21 '20 at 12:48
1

An enum is the best type for the values that can be used in the field signal:

enum SignalType {
  discrete = 'discrete',
  analog = 'analog',
  text = 'text',
}

export interface IChannel {
  title: string
  name: string,
  signal: SignalType[]
  enabled: boolean
  description: string,
  isChangeVisibility: boolean
}
axiac
  • 68,258
  • 9
  • 99
  • 134
  • But this does not constraint the possibility of duplicate keys (?.. – VRoxa May 17 '20 at 11:50
  • 1
    @VRoxa it doesn't, but there's no good way to achieve it any other way than what OP already has, https://stackoverflow.com/a/57021889/1708094 *could* help but IMO it's not worth the effort – paolostyle May 17 '20 at 13:24
  • Another option is to make `signal` a numeric field and use numeric values combined with the bitwise `OR` operator. This has advantages (the duplicate values in its definition do not matter) and disadvantages (the type accepts invalid values, the operations are a bit more cryptic for newbies). – axiac May 17 '20 at 22:07