interface ConfigData { [ key ] : any ; } export class Config { private data : ConfigData = { } ; constructor ( ... data ) { this . merge ( ... data ) ; } of < T > ( section ) { return this . data [ section ] ; } all ( ) { return this . data ; } merge ( ... toMerge ) { Config . merge ( this . data , ... toMerge ) ; } static merge ( ... toMerge ) { const target = toMerge . shift ( ) ; toMerge . forEach ( other => Config . patch ( target , other ) ) ; } static mergeObject ( target , other ) { Object . keys ( other ) . reduce ( ( baseData , targetKey ) => { baseData [ targetKey ] = Config . patch ( baseData [ targetKey ] , other [ targetKey ] ) ; return baseData ; } , target ) ; return target ; } static mergeMap ( target , other ) { other . forEach ( ( value , key ) => { target . set ( key , Config . patch ( target . get ( key ) , value ) ) ; } ) ; return target ; } static patch ( base , value ) { if ( ! value || ! base ) { return value ; } if ( typeof value === 'object' && typeof base === 'object' ) { if ( Array . isArray ( value ) && Array . isArray ( base ) ) { value . forEach ( chunk => { if ( base . indexOf ( chunk ) === - 1 ) { base . push ( chunk ) ; } } ) ; return base ; } if ( base . constructor === Object && value . constructor === Object ) { return Config . mergeObject ( base , value ) ; } } if ( value instanceof Map && base instanceof Map ) { return Config . mergeMap ( base , value ) ; } return value ; } }