Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript Failed to compile because Type declaration of 'any' loses type-safety

How should I address the following error message:

Failed to compile /.../SoftwareLicenseCodes/index.tsx (14,20): Type declaration of 'any' loses type-safety. Consider replacing it with a more precise type. This error occurred during the build time and cannot be dismissed.

See the following code:

import * as React from 'react';
import './SoftwareLicenseCodes.css';

interface SoftwareLicenseCodesProps {
}

interface SoftwareLicenseCodesState {
    count: string;
    oneTimeUsage: boolean;
    duration: string;
    validFrom: string;
    validTo: string;
    distributor: string;
    [key: string]: any;
}

class SoftwareLicenseCodes extends React.Component<SoftwareLicenseCodesProps, SoftwareLicenseCodesState> {
    constructor(props: SoftwareLicenseCodesProps) {
        super(props);

        this.state = {
            distributor: '',
            count:'',
            oneTimeUsage: false,
            duration: '',
            validFrom: '',
            validTo: ''
        };

        this.onInputChange = this.onInputChange.bind(this);
    }

    handleSubmit(event: React.FormEvent<HTMLFormElement>) {
        alert('submit');
        event.preventDefault();
    }

    onInputChange = (event: React.FormEvent<HTMLInputElement>) => {
        const value = event.currentTarget.type === 'checkbox' ? event.currentTarget.checked : event.currentTarget.value;

        this.setState({
            [name]: value
        });
    }

    render() {
        return (
            <div className="user-container software-codes">
                <div className="user-single-container">
                    <h1>Software License Codes</h1>

                    <form className="software-codes__form" onSubmit={this.handleSubmit}>
                        <label>
                            <span className="software-codes__input-element">Count</span>
                            <input
                                name="count"
                                type="number"
                                value={this.state.count}
                            />
                        </label>

                        <label>
                            <span className="software-codes__input-element">Distributor</span>
                            <input
                                name="distributor"
                                type="text"
                                value={this.state.distributor}
                            />
                        </label>

                        <label>
                            <span className="software-codes__input-element">One time usage</span>
                            <input
                                name="oneTimeUsage"
                                type="checkbox"
                                checked={this.state.oneTimeUsage}
                            />
                        </label>

                        <label>
                            <span className="software-codes__input-element">Duration</span>
                            <input
                                name="duration"
                                type="number"
                                value={this.state.duration}
                            />
                        </label>
                        <input className="software-codes__input-element" type="submit" value="Submit" />
                    </form>
                </div>
            </div>
        );
    }
}

export default SoftwareLicenseCodes;
like image 890
user1283776 Avatar asked Oct 19 '25 17:10

user1283776


2 Answers

Your code only sets either string or boolean values, so you could lock it down a bit more:

interface SoftwareLicenseCodesState {
    count: string;
    oneTimeUsage: boolean;
    duration: string;
    validFrom: string;
    validTo: string;
    distributor: string;
    [key: string]: string|boolean;
    // ------------^^^^^^^^^^^^^^
}

Alternately, if you want to have full type safety, you could remove the string index signature and write extra code that switches on the name of the input and then uses an explicit property name. That maximizes your use of type-checking, while (obviously) increasing code size/complexity:

function setNamed(target: SoftwareLicenseCodesState, name: string, value: string|boolean): SoftwareLicenseCodesState {
    if (name === "oneTimeUsage") {
        // Probably add assertion here that value is a boolean
        target.oneTimeUsage = value as boolean;
    } else {
        // Probably add assertion here that value is a string
        const strValue = value as string;
        switch (name) {
            case "count":
                target.count = strValue;
                break;
            case "duration":
                target.duration = strValue;
                break;
            case "validFrom":
                target.validFrom = strValue;
                break;
            case "validTo":
                target.validTo = strValue;
                break;
            case "distributor":
                target.distributor = strValue;
                break;
            default:
                // Failed assertion here
        }
    }
    return target;
}

Then

this.setState(setNamed({}, name, value));

Clumsy as all get-out, but maximizes type-checking.

I really want to find a way for you to use index types, but with the name coming from the name property of an input element, I can't see how to do that without the switch above. Which bothers me, because I seem to recall some uber-clever way of using keyof to build a union type for the name...

like image 80
T.J. Crowder Avatar answered Oct 22 '25 07:10

T.J. Crowder


You can maybe disable this TSLint rule , though I don't know how safe it is :

interface SoftwareLicenseCodesState {
  count: string;
  oneTimeUsage: boolean;
  duration: string;
  validFrom: string;
  validTo: string;
  distributor: string;
  // tslint:disable-next-line: no-any
  [key: string]: any;
}
like image 36
sagi Avatar answered Oct 22 '25 06:10

sagi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!