1
votes

How can I set and existing state field dynamically in a React component?

My current tries lead to the following approach, but it does not work in TypeScript:

export interface MaskCompanyDetailState {
    fieldId: number;
}

export class MaskCompanyDetail extends React.Component<MaskCompanyDetailProps, MaskCompanyDetailState> {

    public constructor(props: any) {
        super(props);

        // Set field defaults.
        this.state = {
            fieldId: 0,
        };
    }

    public componentDidMount() {
        const myField: string = 'fieldId';
        const myVal: number = 123;
        this.setState({[myField]: myVal});
        this.setState({myField: myVal});
    }
}

Error message from TSLint for this.setState({[myField]: myVal});:

Argument of type '{ [x: string]: number; }' is not assignable to parameter of type 'MaskCompanyDetailState | ((prevState: Readonly, props: Readonly) => MaskCompanyDetailState | Pick<...>) | Pick<...>'. Type '{ [x: string]: number; }' is missing the following properties from type 'Pick': fieldId, fieldCompanyName, fieldStreetName, fieldStreetNumber, and 4 more.ts(2345)

Error message from TSLint for this.setState({myField: myVal});:

Argument of type '{ myField: number; }' is not assignable to parameter of type 'MaskCompanyDetailState | ((prevState: Readonly, props: Readonly) => MaskCompanyDetailState | Pick<...>) | Pick<...>'. Object literal may only specify known properties, and 'myField' does not exist in type 'MaskCompanyDetailState | ((prevState: Readonly, props: Readonly) => MaskCompanyDetailState | Pick<...>) | Pick<...>'.ts(2345)

There is already a post here, but I don't see how to apply the suggested IState interface.

1
do you want to add a property to the object ? or else do you want to use value of myField variable to dynamically set property name ?aravind_reddy
Why do you have quotes around the myField key? Kind of defeats the point of a computed property, {['myField']: 123} is the same as {myField: 123}, which I assume isn't what you want to do, I'm guessing myField is a variable, in which case it should be {[myField]: 123}Jayce444
I have updated the post by specifying the initial question and by providing more code.Socrates
Tangentially related: "TSLint" refers to a now-deprecated separate tool. You probably meant "TypeScript" there.Josh

1 Answers

2
votes

Add the following field to MaskCompanyDetailState interface -

[key: string]: any;

i.e.,

interface MaskCompanyDetailState {
    ... // existing fields
    [key: string]: any;
}

It means that you are allowing any property which has a key of type string and value of any type to be set in your state. This is what your linked post says. This is an example of Index Signature which is a feature of Typescript.

It's not really recommended, because it affects readability of your code in the long run and other people in your team may abuse it. But I am not aware of any other solutions to your predicament other than to rethink your design.