Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect "'value' is specified more than once, so this usage will be overwritten. ts(2783)" #38535

Closed
phryneas opened this issue May 13, 2020 · 36 comments · Fixed by #38577
Closed
Assignees
Labels
Bug A bug in TypeScript

Comments

@phryneas
Copy link

phryneas commented May 13, 2020

TypeScript Version: 3.9.2

Search Terms:

  • property-will-be-overwritten-by-spread
  • 2783
  • is specified more than once, so this usage will be overwritten
  • spread

Code

import { Select } from '@material-ui/core';

import React from 'react';

export function Repro({ SelectProps = {} }: { SelectProps?: Partial<React.ComponentProps<typeof Select>> }) {
    return (
        <Select value={'test'} {...SelectProps} />
    );
}

Expected behavior:
No error, as value in SelectProps is optional and SelectProps even defaults to an empty object.

Actual behavior:

'value' is specified more than once, so this usage will be overwritten.ts(2783)
Repro.tsx(7, 32): This spread always overwrites this property.

Playground Link:
none, as the playground does not seem to load the material-ui types

@phryneas phryneas changed the title Incorrect "'value' is specified more than once, so this usage will be overwritten.ts(2783)" Incorrect "'value' is specified more than once, so this usage will be overwritten. ts(2783)" May 13, 2020
@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label May 13, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.0 milestone May 13, 2020
manmorjim added a commit to CartoDB/toolkit that referenced this issue May 14, 2020
The build was failing due to the typescript version `3.9.2` has a bug
microsoft/TypeScript#38535

We will use the version prevous `3.9.2` which is `3.8.3`
manmorjim added a commit to CartoDB/toolkit that referenced this issue May 14, 2020
The build was failing due to the typescript version `3.9.2` has a bug
microsoft/TypeScript#38535

We will use the version prevous `3.9.2` which is `3.8.3`
@Proxxnl
Copy link

Proxxnl commented May 14, 2020

I noticed that this issue has 4.0 as milestone.
If 4.0 will have breaking changes and this bug was introduced in 3.9.2, it might be worth to consider making a fix for this bug in 3.9.x?

@AlexanderVishnevsky
Copy link

Same problem with

   "@material-ui/core": "4.9.14",
   "typescript": "3.9.2",

Reverting typescript to
"typescript": "3.8.3",
solves the problem.

@yamuun
Copy link

yamuun commented May 19, 2020

I'm worried
Is belowCode Same Problem ?

Reverting typescript to
"typescript": "3.8.3",
solves the problem.

TypeScript Version: 3.9.2

https://www.typescriptlang.org/play/#code/MYewdgzgLgBADgUwE4XDAvDA3gKBvmAQwHMEAuGAJgAYAaPAgMwEsUoA5QgW3JgHIAUiAAWYPvQIwANoWiceFPgGEQIANbicAXwDcOUJBBSEAOikhiACkQpwASj37w0GMIsIM2BvhK8aEgkIkBEJFdgBNTUkoZihjRQBlQmMIGABZQjBfJCiCE3ybVDB6XRwnQ2MzC0s3UgcygxdahGbPXEl8k0LwAJ9SCn9vImDQ-gjc-Bi43j4klPTM7M1tPUajU3MrZub6oA

Code

const person = {
    age: 25,
    firstName: 'John',
    lastName: 'Cook',
};
console.log(person);

//'age' is specified more than once, so this usage will be overwritten.(2783)
//input.ts(12, 5): This spread always overwrites this property.
const hoge = {
    age: 20,
    area: 'NY',
    title: 'Sales Manager',
    ...person,
};

console.log(hoge);

//noProblem
const hogehoge = {
    ...person,
    age: 20,
    area: 'NY',
    title: 'Sales Manager',

};
console.log(hogehoge);

@artem-malko
Copy link

artem-malko commented May 19, 2020

@yamuun it's useless to write

const hoge = {
    age: 20,
    area: 'NY',
    title: 'Sales Manager',
    ...person,
};

cause age won't be 20 in hoge. The spread always overwrites age property. So, it's ok to see "This spread always overwrites this property".

@DanielRosenwasser
Copy link
Member

Should be fixed now

@b2whats
Copy link

b2whats commented May 20, 2020

@DanielRosenwasser
3.9.3 not work

@DanielRosenwasser
Copy link
Member

@weswigham ?

@weswigham
Copy link
Member

I'm not sure what you want from me, but:

  • The original issue is fixed, and published in version 3.9.3, as indicated by the milestone and associated PR activity.
  • @AlexanderVishnevsky commented between us closing the issue and publishing 3.9.3, so didn't have the patch (his comment includes a reference to 3.9.2)
  • @yamuun is just confused about the error message (which is in his case correctly issued, as @artem-malko explained) and likely posted here because the recent activity is making this issue rank higher than relevant stackoverflow posts (probably), and
  • I don't know what @b2whats is in here for, since the original issue is definitely fixed. If he's still having some kind of a problem, we'll definitely need to know more than "3.9.3 not work".

@yogeshkotadiya
Copy link

The issue is not resolved in 3.9.3

'addressNickName' is specified more than once, so this usage will be overwritten.
const data: Address = {
	addressNickName: "Home",
	streetName: "12th Street",
   	...payload,
};

@phryneas
Copy link
Author

phryneas commented May 21, 2020

@yogeshkotadiya without knowing the type of payload, that message can be perfectly valid.
Does the type of payload contain a non-optional addressNickName property?
Then the message is correct and telling you that addressNickName: "Home" will always be overridden by payload.addressNickName so you can leave it out. In that case, it is not this bug.

devtools-bot pushed a commit to ChromeDevTools/devtools-frontend that referenced this issue May 27, 2020
I was hitting a bug in 3.9.2 with the breadcrumbs CL [1] that is fixed
in 3.9.3 via this PR [2]. (I've verified locally that it is fixed).

[1]: microsoft/TypeScript#38535
[2]: microsoft/TypeScript#38577

DISABLE_THIRD_PARTY_CHECK=typescript update


Change-Id: Ia874e5936a5bbf0bf26f751ab746976f71910f25
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2218013
Commit-Queue: Jack Franklin <[email protected]>
Auto-Submit: Jack Franklin <[email protected]>
Reviewed-by: Tim van der Lippe <[email protected]>
babot pushed a commit to binaryage/dirac that referenced this issue May 28, 2020
I was hitting a bug in 3.9.2 with the breadcrumbs CL [1] that is fixed
in 3.9.3 via this PR [2]. (I've verified locally that it is fixed).

[1]: microsoft/TypeScript#38535
[2]: microsoft/TypeScript#38577

DISABLE_THIRD_PARTY_CHECK=typescript update


Change-Id: Ia874e5936a5bbf0bf26f751ab746976f71910f25
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2218013
Commit-Queue: Jack Franklin <[email protected]>
Auto-Submit: Jack Franklin <[email protected]>
Reviewed-by: Tim van der Lippe <[email protected]>
@phryneas
Copy link
Author

phryneas commented Jun 19, 2020

@master117 You are spreading an array into an object spread there. That probably does not do what you want anyways.
I'm not even sure if that is defined JS behaviour.

Or rather, realistically, your JS is fine: but the return type of your method is Array<Object> even though it should probably more look like Record<string, Object> or Record<number, Object> depending on what your keys are. It's definitely not an array though, since you are initializing it with {}.

@master117
Copy link

master117 commented Jun 19, 2020

@phryneas Thanks for the fast reply. I made a typo, already fixed, the return is obviously Object not Object[].

The objects will be something like:
{ prefixedVariablename: any, prefixedVariablename2: any, prefixedVariablename3: any }
Which I wouldn't know how to type better than Object.

But it seems that removing the [] has resolved the error. So Object works fine, but Object[] doesn't. My problem is solved :)

I would have assumed something like [{key: value}, {key: value}] should work as well. Or rather throw a different type of error. As we then end with

params: {
        limit: this.state.rows,
        offset: this.state.offset,
        sort: this.getSortString(),
        {key: value},
        {key: value}
      },

@phryneas
Copy link
Author

Well, in this case the error was entirely accurate, as you were spreading an object with a defined sort property (the array type) on top of an object with a sort property. So that explains why you were getting it.

@master117
Copy link

with a defined sort property (the array type)

Aaaah, of course, thank you again.

@simeyla
Copy link

simeyla commented Jun 26, 2020

Funny thing about all this is sometimes I deliberately put a redundant property in a list - from a readability standpoint so it's clear what the intent was. Or as a quick fix when I had bad data that didn't conform to the typescript interface.

As others have said, can fix putting the ...spread before the redundant properties.

@kevbost
Copy link

kevbost commented Jun 29, 2020

FWIW, for people like me who find themselves on this thread, this problem is resolved in React by including the prop after a spread:

// Error:
image

// No error:
image

@phryneas
Copy link
Author

Which has a different runtime behaviour and exactly what the error is warning about.
In the first case, assuming the types were correct, iconOnly would always be overwritten and never actually have that value. You probably don't intend that, which is why you get the error.

@krasevych
Copy link

Same problem with 3.9.6

@ziccardi
Copy link

ziccardi commented Jul 10, 2020

I have the exact same error with the test code below (I tagged the failing line with a '<===' comment): it says name is specified more than once, but

  1. customAttrs is defined as Record<string, string>. It can contain name but it could not contain it either.
  2. genRandomVariantDef doesn't return the name` key

Where is name specified more than once?

   generateVariants: (upsMock: UPSMock, appId: string, count: number, customAttrs?: Record<string, string>[]) => {
    const VARIANT_NAME_PREFIX = 'TEST VARIANT';

    const variants = [];

    const genRandomVariantDef = () => {
      if (Math.round(Math.random() * 10) % 2 === 0) {
        // Android variant
        return {
          type: 'android',
          googleKey: '123456',
          projectNumber: '1234556',
        } as AndroidVariant;
      } else {
        // iOS variant
        return {
          type: 'ios',
          production: false,
          certificate: '123',
        } as IOSVariant;
      }
    };

    for (let i = 0; i < count; i++) {
      variants.push(
        upsMock.getImpl().createVariant(appId, {
          name: `${VARIANT_NAME_PREFIX} ${i}`,  // <======. 'name' is specified more than once, so this usage will be overwritten.
          developer: 'admin',
          variantID: Guid.raw(),
          ...(customAttrs ? customAttrs[i] : genRandomVariantDef()),
        } as Variant)
      );
    }
    return variants;
  }

@phryneas
Copy link
Author

@ziccardi this looks legit. You should probably open a new Issue for that, as it is a different bug, even though it results in the same error message (this one has definitely been fixed).
Commenting on a closed issue has very low chances of this being resolved.

@ziccardi
Copy link

@phryneas 👍

@ziccardi
Copy link

@phryneas nvm. I leave it here for the log: when I was trying to create a simple snippet to replicate the issue, I noticed it was compiling fine. So the solution jumped to my mind. The error resides in the as AndroidVariant and as IOSVariant since they both inherit from Variant whose definition is:

export interface Variant {
  id: string;
  variantID: string;
  name: string;
  description: string;
  developer: string;
  secret: string;
  type: VariantType;
  metadata?: {
    activity: number;
    deviceCount: number;
  };
}

So, even if I don't really specify the name two times, since it is defined as mandatory in the base interface the compiler sees it as specified 2 times: my error, compiler was right.

@nisimjoseph
Copy link

I am using TS 3.9.6 and the issue still exist. see the simple code here:

interface Config {
	Version:string;
	publisher:string;
}

function send(config:Config) {
	const finalConfig:Config = {
		publisher: "name",
		Version: "1.0",
		...config,
	}
}

Get error: TS2783: 'publisher' is specified more than once, so this usage will be overwritten.
When I do ...<any>config, it pass, but I do want the static check which I can't get now.

@ziccardi
Copy link

@nisimjoseph The reason is that in the Config interface the publisher and Version fields are mandatory, so the compiler expects that the config object already has those fields.
You can fix it by changing the Config interface to:

interface Config {
	Version?:string;
	publisher?:string;
}

@nisimjoseph
Copy link

nisimjoseph commented Jul 15, 2020

Thank you on the quick response.
Those values come from JS and not supposed to be Optional. they are mandatory , so I set the default values and then override the values with the ones I got from outside.
I also have some levels of objects inside the config with their own default values. I don't want to make it optional so the entire project will start to highlight fields as "optional" and I will need to add item existing check.
in addition, the Config has lots of keys/objects and it will create too many optional.

@ziccardi
Copy link

@nisimjoseph Yes, but the values you "get from the outside" are into an object that implements the Config interface. Since the Config interface says both publisher and Version are mandatory, the compiler supposes that config always has both of them, thus always overwriting your 'default' values (hence the specified more than once error)

@nisimjoseph
Copy link

nisimjoseph commented Jul 15, 2020

@ziccardi I see your point, but this is not the case here.
the Config Interface, in this example, doesn't need to have all params from outside, only part of them and also it in JS and not TS like the source code.
The reason it is mandatory is I am filling all default (missing) values so the TS compiler will know all data exist for 100% of fields and won't gives errors on the optional fields all over the code.

Just think I have 20 configurations properties and I know not each client will need all of them and will set them in runtime in JS.
I just note it because I see it a lot as default values when init data.

@ziccardi
Copy link

@nisimjoseph If the object you are receiving does not contains all the mandatory fields, then it is not a Config object. The easiest solution I see to do what you want is changing your code to

function send(config:Config) {
	const finalConfig:Config = {
		publisher: "name",
		Version: "1.0",
   		...config as {},
	}
}

Anyway, this is not a bug: compiler is right.

@nisimjoseph
Copy link

love the ...config as {}, solution. it working well, thank you.

@nisimjoseph
Copy link

nisimjoseph commented Jul 15, 2020

@ziccardi I notice when I am using the following it gives me also nested object errors, which is better (use Partial).

interface Config {
	Version:string;
	publisher:string;
}

function send(config:Partial<Config>) {
	const finalConfig:Config = {
		publisher: "name",
		Version: "1.0",
		...config,
	}
}

And, I know the compiler is working fine, I was surprised it added in 3.8.x without a tsconfig way to disable it.

@Vladyslav-Apukhtin
Copy link

Vladyslav-Apukhtin commented Jul 17, 2020

@nisimjoseph this is working for me:

interface Config {
	Version:string;
	publisher:string;
}

function send(config:Config) {
	const finalConfig:Config = {
                ...config,
		publisher: config.publisher || "name",
		Version: config.Version || "1.0"
	}
}

@nisimjoseph
Copy link

thank you @Vladyslav-Apukhtin, it will work in this way but I can drop the use of ...config,.

bumi added a commit to bumi/joule-extension that referenced this issue Jul 29, 2020
The use of the spread opertor causes issues in TypeScript 3.9.x
To avoid this issue we use Object.assign to return on object with
default values.

TypeScript error:
error TS2783: '<XYZ>' is specified more than once, so this usage will be overwritten.

See Travis build with errors:
https://travis-ci.org/github/joule-labs/joule-extension/builds/713053315

Related TypeScript issues:

microsoft/TypeScript#39671
microsoft/TypeScript#38535
@Talent-Rain
Copy link

  • In my opinions, you would like to change the property value in your mind ,but not for the props ;so you should put the {... SelectProps} before the value you write
  • otherwise, your value will be change by SelectProps and ts will think that you do the unnecessary thing, and ask you to delete the value property you write which can't change anything

@phryneas
Copy link
Author

phryneas commented Nov 4, 2020

@Talent-Rain

  • SelectProps is a Partial property. This means every of it properties can be there, but it could also be not. It will not necessarily be overridden, but it could be. Which is fine, and a case where that error message should not have shown up.
  • This was a bug report. It was accepted as a bug. It was fixed. 6 Months ago. It does not happen again. Everyone who posted here after that had another problem or did not correctly interpret the error message that was correctly shown to them for reasons unrelated to this bug.

Could we please stop posting unrelated stuff here? This issue has been fixed and everything after that is either worthy of a new ticket or not of interest any more, as this bug has been fixed.

@microsoft microsoft locked as resolved and limited conversation to collaborators Nov 4, 2020
@RyanCavanaugh
Copy link
Member

I agree 👆

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.