Search code examples
reactjstypescriptinitializationfactory-pattern

How to centralize interface initialization in React project with Typescript


I have a React project in Typescript and in many of my components I use an interface inside the State:

interface Item {
    selectedValue: string
    originalSelectedValue: string
    loading: boolean
    disabled: boolean
    isValid?: boolean
}

interface State {
   itemInstance: Item
}

In every component I use the constructor in order to initialize the instance of the interface:

constructor(props: Props) {
        super(props);

        let itemInstance: Item = {
             selectedValue: '',
             originalSelectedValue: '',
             loading: true,
             disabled: false,
             isValid?: false
        };

        this.state = {
           itemInstance: itemInstance
        }
}

Since I need to repeat this initialization for every component, instead of copy/pasting the code in every component I was tryign to find a way to centralize the initialization. Since the interface cannot have implementation, I thought to implement some sort of Factory Method Pattern without usign a class:

     export const getItemInstance = (): Item  => {
        return ({
                 selectedValue: '',
                 originalSelectedValue: '',
                 loading: true,
                 disabled: false,
                 isValid?: false
       });
    }

Although I am not really keen on this solution, since for every Interface I need to create another file/component that implements the initialization. Does anybody know a pattern to implement this behaviour in Typescript?


Solution

  • I know you mentioned you don't want to use class but I'd probably just introduce a class implementing the interface anyway. Then you just make an instance via one line:

    interface IItem {
        selectedValue: string
        originalSelectedValue: string
        loading: boolean
        disabled: boolean
        isValid?: boolean
    }
    
    class DefaultItem implements IItem {
      constructor(
        public selectedValue = '',
        public originalSelectedValue = '',
        public loading = true,
        public disabled = false,
        public isValid = false
      ) {}
    }
    

    Then inside your component:

    constructor(props: Props) {
      super(props);
    
      const itemInstance = new DefaultItem();
    
      this.state = {
        itemInstance
      };
    }
    

    Not only this reads much better but when you want to change a default value of one specific property for all instances, you do it in one place.