0

I'm trying to upgrade my typescript dependency (2.5.x > 3.1.3) in my React-Redux project. Sadly not without problems :P

I have a base selectpicker React component that expects a function property with a parameter of type IdNameObject:

onToggleItem: (item: IdNameObject) => void;

The actual function that gets injected into the function prop, is a Redux dispatch function with a parameter of an interface that extends the IdNameObject:

updateSelectedLocation: (location: Location) => void;
interface Location extends IdNameObject {...}

Typescript now throws an error saying that type Location is not equal to type IdNameObject, obviously.

I tried converting the function property to make it generic:

onToggleItem: <T extends IdNameObject>(item: T) => void

This however still throws a typescript error:

type '(location: Location) => void' is not assignable to type '<T extends IdNameObject>(item: T) => void'

Any idea what I should be doing in this case?


Full example case

I left out all the extra code that is not really needed for this case.

On one side I have a navigation.tsx:

interface Location extends IdNameObject {...}

interface Props {
    updateSelectedLocation: (location: Location) => void;
}

class Navigation extends React.Component<Props> {
    public render(): any {
        const {updateSelectedLocation} = this.props;
        return <Selectpicker onToggleItem={updateSelectedLocation}/>;
    }
}

function mapDispatchToProps(dispatch: DispatchType) {
    return {
        updateSelectedLocation: (location: Location) => {
            dispatch(updateSelectedLocation(location));
        },
    }
}

export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)((Navigation as any));

On the other side i have a selectpicker.tsx:

interface Location extends IdNameObject {...}

interface Props {
    onToggleItem: (item: IdNameObject) => void;
}

export class Selectpicker extends React.Component<Props> {
    public render(): any {
        const {onToggleItem} = this.props;
        return <Dropdown contentOnToggleItem={onToggleItem}/>;
    }
}

1 Answer 1

1

By defining the type parameter T on onToggleItem, you've said that every caller of the selectpicker component has to provide an onToggleItem implementation that works for every T. What I think you want is that the caller of the selectpicker component chooses the type T of the objects being selected when constructing the selectpicker and then provides an onToggleItem implementation that works for that specific T. To do that, T should be defined on the selectpicker component and on the props interface that contains onToggleItem (if you're using one), not on onToggleItem itself.

If you're having trouble making this work, please add more of your code (at a minimum, the declaration of the selectpicker class) to the question.

Update

Based on the example code, here is how you would add T to selectpicker.tsx:

interface Props<T extends IdNameObject> {
    onToggleItem: (item: T) => void;
}

export class Selectpicker<T extends IdNameObject> extends React.Component<Props<T>> {
    public render(): any {
        const {onToggleItem} = this.props;
        return <Dropdown contentOnToggleItem={onToggleItem}/>;
    }
}

Then, in navigation.tsx, TypeScript should infer that your <Selectpicker ... /> element is using T = Location. You can also explicitly specify <Selectpicker<Location> ... />.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @MattMcCutchen! I think I understand what you mean, but am having trouble implementing it. I updated my first post with a bigger code example.
thanks a lot! Worked through everything :) The only problem I ended up with was in an underlying redux connect function. export default connect<StateProps, DispatchProps, OwnProps<any>>(mapStateToProps)((MultiColumnDropdown as any)); OwnProps needed to get the <T extends IdNameObject>, but I could not find a correct place to put that, therefore the any type. This seems to not have any effect on the typings in the MultiColumnDropdown class itself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.