1

I need to define an object that has an array of strings, but the string can only accept certain values. The examples below are the possible scenario:

let user = {
   name: 'John',
   communicationPreferences: ['email', 'whatsApp']
}

or

let user = {
   name: 'John',
   communicationPreferences: ['whatsApp', 'weChat', 'skype']
}

or

 let user = {
   name: 'John',
   communicationPreferences: ['email', 'whatsApp', 'weChat', 'skype', 'line', 'sms']
 }

4 Answers 4

1

You have a some options depending on your exact situation:

Enum: Provides flexible, type-safe definition of your values that allow for run-time look-ups and reverse look-ups. This is likely your preferred solution:

enum Channel {
    Email = 'email', // if you prefer email = 'email', etc. that's also very doable
    WhatsApp = 'whatsApp',
    WeChat = 'weChat',
    Skype = 'skype',
    Line = 'line',
    SMS = 'sms',
}

class User {
   constructor(private name: string, private communicationPreferences: Channel[]) { };
}

const john = new User('john', [Channel.SMS]); // {name: 'john', communicationPreferences: ['sms']);

// example of reverse look-up
const channel = 'skype'; // from some unverified source
if (Channel[channel] === undefined) {
   // handle error case at run-time
}

Union Type: If you wanna be quick and dirty about it, you can use a string literal union type. This would provide compile-time only safety, or if you have a very extreme case where you want to limit the (very small) overhead of an Enum:

type Channel = 'email'| 'whatsApp'| 'weChat' | 'skype' | 'line'| 'sms';

interface User {
   name: string;
   communicationPreferences: Channel[];
}

const john: User = {
    name: 'john',
    communicationPreferences: ['telegraph']; // would fail to compile
}

Index Type: Your last option would be combining the keyof and typeof operators to produce a dynamic union type. This might be useful if your communication channel options are coming from an external JSON/JS file, especially if it may change:

// Some example object you're getting

const channels = {
   skype: { ... },
   sms: { ... },
   line: { ... },
   // and so on
}

// in your script
type Channel = keyof typeof channels; // "skype" | "sms" | "line" | ...

In your situation, you might also be interested in the Set class; it provides a distinct (only one of each value allowed) collection:

// define Channel type, from options above

class User {
    private communicationPreferences: Set<Channel>;

    constructor(private name: string, channels: Channel[]) {
        this.communicatonPreferences = new Set<Channel>(channels);
    }

    public serialize() {
        return {
            name: this.name,
            communicationPreferences: Array.from(this.communicationPreferences)
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

To achieve this I would build a strongly Typed object using Enums like this:

export enum ChannelCommunication {
        whatsApp = 'whatsApp',
        weChat = 'weChat',
        skype = 'skype',
        email = 'email',
        line = 'line',
        sms = 'sms'
    }

    export class User {

        private _name: String;
        private _communicationPreferences: ChannelCommunication[];

        constructor(name:String, communicationPreferences: Array<ChannelCommunication>) {
            this._name = name;
            this._communicationPreferences = communicationPreferences;
        }
        public name: String;
        public communicationPreferences: ChannelCommunication[]
    }



    let communicationPreferences: ChannelCommunication[] = [ChannelCommunication.email,
 ChannelCommunication.line,
 ChannelCommunication.skype,
 ChannelCommunication.sms,
 ChannelCommunication.weChat,
 ChannelCommunication.whatsApp];

let user = new User('John',communicationPreferences);

Hope it answers your question

Comments

0
type CommunicationPreferences = 'email' | 'whatsApp' | 'weChat' | 'skype' | 'line' | 'sms';

interface User {
    name: string;
    communicationPreferences: CommunicationPreferences[];
}

let user : User = {
    name: 'John',
    communicationPreferences: ['email', 'whatsApp', 'weChat', 'skype', 'line', 'sms']
}

Comments

0

Typescript allow usage of Enum:

export enum communicationPreferences{
whatsApp=0
weChat=1
skype=2
}

var value: communicationPreferences=communicationPreferences[communicationPreferences.whatsApp]

beware of trying to use something like communicationPreferences.whatsApp by itself which returns the integer value.

seems like typescript 2.4 now support string-based enum so we dont even need to do the integer stuff and just declare whatsApp="whatsApp"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.