10

Consider this example

interface additonalProperties {
  backgroundColor: string,
  color: string,
  [key: string]: string
}

class StyleObjectMaker implements StyleObjectMaker {
  constructor(className: string, additonalProperties: additonalProperties = {}) {
    this.key = `button`
    this.className = `button${className ? '-' + className : ''}`
    this.property = {
      backgroundColor: colors[className] || colors.default,
      color: colors.default,
      ...additonalProperties
    }
  }
}

In the above ts is complaining about

'backgroundColor' is specified more than once, so this usage will be overwritten

And same for

  color

Any idea how I can fix it? i.e how can I allow to overwrite

This is how my tsconfig looks

{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "outDir": "dist/ts-out",
    "sourceMap": true,
    "strict": true,
    "target": "es2017",
    "resolveJsonModule": true,
    "typeRoots": ["./node_modules/@types"]
  },
  "compileOnSave": true,
  "include": ["src", "index.ts"]
}
Alwaysblue
  • 9,948
  • 38
  • 121
  • 210

4 Answers4

16

Typescript is pointing out that these two lines are useless:

  backgroundColor: colors[className] || colors.default,
  color: colors.default,

You're setting these properties manually, but then you immediately spread over them, wiping them out. This is probably not what you meant to do. If you want these two values to trump what's found in additionalProperties, then switch the order:

this.property = {
  ...additonalProperties
  backgroundColor: colors[className] || colors.default,
  color: colors.default,
}

If the order is correct, but additionalProperties won't always have color and backgroundColor, then mark those as optional:

interface additonalProperties {
  backgroundColor?: string,
  color?: string,
  [key: string]: string
}

Or if it's behaving the way you want (ie, the properties are always getting overwritten, and that's intentional), then delete the useless lines of code.

Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • I want to override those properties. There are meant to be default values `this.property = { backgroundColor: colors[className] || colors.default, color: colors.default,` If user passes the values to the class constructor which may also include `colors` or `background`. I want to override those properties – Alwaysblue Jun 26 '20 at 18:45
  • `If user passes the values to the class constructor` the word "if" suggests you mean for them to be optional. Right now, you've marked them as mandatory. So it sounds like you want my second suggestion: make them optional. – Nicholas Tower Jun 26 '20 at 19:00
  • Yeah, The warning was correct. I was doing something wrong. Typescript is love. Thanks – Alwaysblue Jun 26 '20 at 22:04
2

Typescript's Partial utility type seems the best way to make this happen.

In your example, the constructor would be changed to:

constructor(className: string, additonalProperties: Partial<additonalProperties> = {})
Seth Bro
  • 2,537
  • 3
  • 19
  • 15
1

I don't know if there is a configuration for this. However, you could destructure additionalProperties to exclude color and backgroundColor:

class StyleObjectMaker implements StyleObjectMaker {
  constructor(className: string, additonalProperties: additonalProperties = {}) {
    const { backgroundColor, color, ...rest } = additionalProperties;
    this.key = `button`
    this.className = `button${className ? '-' + className : ''}`
    this.property = {
      backgroundColor: colors[className] || colors.default,
      color: colors.default,
      ...rest
    }
  }
}

If you want those props to be just default values, you can make use of Object.assign.

class StyleObjectMaker implements StyleObjectMaker {
  constructor(className: string, additonalProperties: additonalProperties = {}) {
    const finalProperties = Object.assign({}, {
        backgroundColor: colors[className] || colors.default,
        color: colors.default,
    }, additionalProperties);
    this.key = `button`
    this.className = `button${className ? '-' + className : ''}`
    this.property = finalProperties;
  }
}
Federico Alecci
  • 914
  • 6
  • 14
  • want to override those properties. There are meant to be default values this.property = { backgroundColor: colors[className] || colors.default, color: colors.default, If user passes the values to the class constructor which may also include colors or background. I want to override those properties – Alwaysblue Jun 26 '20 at 18:46
  • @HardikKhanna I updated my answer to show how to make use of Object.assign for default values – Federico Alecci Jun 26 '20 at 18:50
1

I had some defaults set like this that weren't a problem until Typescript 4.4 (possibly an earlier version) :

    const formsValue = { 

        stateOrProvince: null, 
        stateCd: null, 
        address3: null, 
        phone: null, 

        ...addressFields 
    };

I was now getting the error Error TS2783: 'stateOrProvince' is specified more than once, so this usage will be overwritten. which makes sense.

The destination for this value is an Angular form which requires empty fields to be explicitly set. While normally addressFields would contain a value for every field (as specified by its type) I had some older customers who may have a cached value in their local storage without all these fields hence these defaults.

Fortunately the following seems to get around the error, and I think looks nicer anyway as it groups things together.

    const formsValue = { 

        ...{
            stateOrProvince: null, 
            stateCd: null, 
            address3: null, 
            phone: null, 
        },

        ...addressFields 
    };

Not 100% sure why the compiler lets this through but it does :-)

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689