How to get Typescript to recognise generic commonalities between two of the same type of interface in a union?

Viewed 73

I have a few types outlined as such:

interface Person {
    name: string;
}
interface Core<T> {
    fnc: (arg: T) => void;
    args: T;
}
interface One extends Core<Person> {
    type: 'modifyPerson';
}
interface Two extends Core<Person & { age: number }> {
    type: 'modifyAgeingPerson';
}

I then have a function which can handle both modifying a shared property of a person or an ageing person - as such it has a union type, an example would be as follows:

modifyPersonCharacteristics(person: One | Two) {
    person.fnc({ ...person.args, name: 'Steven' });
}

Typescript however doesn't like this due to the fact that there's type overlap - but in this case because of the use of a generic should it even matter? either an instance of a One or Two could both accept the arguments passed.

Is there a way to get typescript to look at the bigger picture of the generic?

A side note is that the following works, but for obvious reasons I'd rather not:

modifyPersonCharacteristics(person: One | Two) {
    if (person.type === 'modifyPerson') {
        person.fnc({ ...person.args, name: 'Steven' });
    } else {
        person.fnc({ ...person.args, name: 'Steven' });
    }
}
1 Answers

I think your problem is that you are defining the parameter of fnc too narrowly. To your point about the bigger picture--the point is that your fnc will work with any type that extends (or intersects) Person, so it just needs to be declared that way, as so

interface Person {
    name: string;
}
interface Core<T> {
    fnc: (arg: Person) => void;  //This is the line that's changed.
    args: T;
}
interface One extends Core<Person> {
    type: 'modifyPerson';
}
interface Two extends Core<Person & { age: number }> {
    type: 'modifyAgeingPerson';
}

function modifyPersonCharacteristics(person: One | Two) {
    person.fnc({ ...person.args, name: 'Steven' });
}

Playground here.

Related