Home > Mobile >  The intersection '... & ...' was reduced to 'never' because property '...&#
The intersection '... & ...' was reduced to 'never' because property '...&#

Time:01-19

I have a two classes defined as following:

class FirstClass {
  values: FirstValuesType = {} as FirstValuesType;

  setValues(values: FirstValuesType): void {
    this.values = { ...values };
  }
}

class SecondClass {
  values: SecondValuesType = {} as SecondValuesType;

  setValues(values: SecondValuesType): void {
    this.values = { ...values };
  }
}

interface CommonValuesType {
    id: number;
    property1: string;
    property2: string;
}

enum FirstReasonEnum {
    A, B, C
}

enum SecondReasonEnum {
    X, Y, Z
}

interface FirstValuesType extends CommonValuesType {
  reason: FirstReasonEnum;

}

interface SecondValuesType extends CommonValuesType {
  reason: SecondReasonEnum;
}

And then I defined a constant which can be one of the classes as following:

const model: FirstClass | SecondClass;

When I call setValues like this:

model.setValues(newValues);

I get the following ts error:

  Argument of type '{ id: number; property1: string; property2: string; reason: FirstReasonEnum; }' is not assignable to parameter of type 'never'.
  The intersection 'FirstValuesType & SecondValuesType' was reduced to 'never' because property 'reason' has conflicting types in some constituents.(2345)

How can I solve this ?

Edit:

Here is the link to the playground:

https://www.typescriptlang.org/play?ts=4.3.5#code/FDDGBsEMGdoAgGIEsBO0AuBhKs4G9g44A3ScAVwFNoAuRVDANTKugBUBPAB0rgF58AXzgx6adMwrVOPANwgi0ShJbUAFKSm0xTVe26UAlHWIB7JABN8hInHQALJNAB0m1v3xxn3t9TiD5IkFgYLAceABlSlBTADsLbBh4AiJfbSiY MlWGV4BPGFRDLiLbOkDeRslFS0NPTpirL1c4xJzKxTbBydXPQ88Lx8 gJtg0KRY9EoUADNIUF5MUwBbZbiy-R5rWzhLOljyZYAjacDbLhRTHhR0DgBGOgwUCYBzM6ILq nbgCZH9GesTeIRAlAOyx06AASpQYHEAKLg7a2ACCABo4AAhDGYEHAMGHOCNCwwuGxRGEzpEAAaGIAmhiAFp4iZTWbzXjIcQbXJwSgADym8XgS1W62aBmRKFh0DidC5GFJsvJ4Mq40m0zmCyJ0RKPMlAqFFhFKzWsX1W060rJDV18SVCNVeIgSTgAFkOIlcJ0QDYJkh0GoAPprCyUcDyhhYcJwAA OsyCXChmRREyGDgofDkfEXvg8eJeY8IdMYfAlR26fQcFilAA7ht jYdns7mjm dLtdbg84AByT7d 599s7D5d74cP79weTn4jjtEa3KnOKmWOw7OdEd4JjzOl8POaobNS1ht6QzvfwgQRAA

CodePudding user response:

Your code assumes that model is an instance of FirstClass, but the types say that it could be an instance of FirstClass or it could be an instance of SecondClass. Since it's unclear which it is, but setValues needs to know, TypeScript is highlighting for you that the argument you're passing isn't valid (or perhaps I should say might not be valid). And it can't be valid, because it can't be simultaneously both a FirstValuesType and a SecondValuesType (which is what FirstValuesType & SecondValuesType means), since the types of reason differ.

The minimum-changes way to solve it is to test what you have to see whether it's a FirstClass instance, which you can do since you've used a class (not just an interface). So this fixes it:

if (model instanceof FirstClass) {
    model.setValues(newValues);
} else {
    // ...code here to do something with the `SecondClass` `model`
}

Playground example


That said, you might want to reconsider the overall structure, but it really depends on the specifics and this looks like a simplified example (appropriately simplified, for the purposes of asking the question). FirstClass and SecondClass, and FirstValuesType and SecondValuesType, are identical other than the type of the enum used for reason. You might consider using generic type parameters on a single TheClass and ValuesType instead. But that wouldn't change the fundamental issue that the code in init is assuming that the model is one thing when it may be one or the other of two things.


Side note: This part of the init code seems slightly suspicious:

const model: TheClass<EnumType> = _model;
// ...
model.setValues(newValues);

The model constant and the _model parameter point to the same object, so it would be more direct to not create an unnecessary additional identifier and just use _model directly:

_model.setValues(newValues);

Either way, you're modifying the object that was passed in. (If you meant to copy the object, you'll need to do a copy operation.)

  • Related