Warning when passing a function to a wrapped component prop - reactjs

At present I have a ValidatedTextField component that wraps a TextField component and takes in a validationerror property that is used to communicate between the child and parent and consumed by either the onChange or onBlur event of the textbox.
However when passing a function to this attribute I receive the following error:
Invalid value for prop validationerror
on tag. Either remove it from the element, or pass a string or number value to keep
it in the DOM. For details,
see https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html#changes-in-detail
I have read through the link which says that data and aria attributes can still be passed freely, however switching to using data attribute results in the same error. I cannot think how else to send the function to update the parents error back.
From the wrapper
<ValidatedTextField
type="text"
variant="standard"
required={true}
validateon={'onChange'}
validate={[Validations.Required, Validations.allowedNameCharacters]}
validationerror={(validationError: boolean) => this.setState({ HasError: validationError }) }
onChange={(event: any) => this.setState({ textboxvalue: event.target.value })}
value={this.state.textboxvalue}
/>
and the wrapped component
import * as React from 'react';
import * as _ from 'lodash'
import { IValidationItem } from '../../../Interfaces/IValidationItem'
import TextField, { TextFieldProps } from "#material-ui/core/TextField";
interface IValidatedTextFieldProps {
validate?: IValidationItem[],
validateon?: 'onBlur' | 'onChange',
validationerror?: (hasError?: boolean) => void
}
interface IValidatedTextFieldState {
validationErrorMessage: string,
validationError: boolean
}
type ValidatedTextFieldAllProps = IValidatedTextFieldProps & TextFieldProps
class ValidatedTextField extends React.Component<ValidatedTextFieldAllProps, IValidatedTextFieldState> {
public constructor(props: ValidatedTextFieldAllProps) {
super(props);
this.state = {
validationErrorMessage: "",
validationError: false
}
}
public validationWrapper = (event: any) => {
const { validate, } = this.props;
return !validate ? "" : _.forEach(validate, (validationItem: IValidationItem) => {
const result = !validationItem.func(event.target.value)
if (result) {
this.setState({ validationErrorMessage: validationItem.validationMessage });
this.setState({ validationError: result })
this.callParentValidationErrorMethod(result)
return false;
}
else {
this.setState({ validationErrorMessage: "" });
this.setState({ validationError: result })
this.callParentValidationErrorMethod(result)
return;
}
});
};
public onBlurValidation = (event: any) => {
const { onBlur, validateon, validate } = this.props;
if (_.isFunction(onBlur)) { onBlur(event); }
if (validateon === "onBlur" && !!validate) { this.validationWrapper(event);
}
public onChangeValidation = (event: any) => {
const { onChange, validateon, validate } = this.props;
if (_.isFunction(onChange)) { onChange(event); }
if (validateon === "onChange" && !!validate) { this.validationWrapper(event); };
}
public callParentValidationErrorMethod = (hasError: boolean) => {
if(_.isFunction(this.props.validationerror)) {
this.props.validationerror(hasError);
}
}
public render() {
const { validationErrorMessage, validationError } = this.state
return (<TextField
{...this.props}
onBlur={(event: any) => { this.onBlurValidation(event); }}
onChange={(event: any) => { this.onChangeValidation(event); }
}
error={validationError}
helperText={validationErrorMessage}
/>)
}
}
export default ValidatedTextField;
Additional info: Not seen in IE only chrome so far and currently React v16.6

Alright Solved
Issue was that I was spreading all properties on the textfield in the component including the non existent attributes on the textfield.
Extrapolating the properties I did not need and only binding the default text field properties fixed this issue
const {validationerror,validate,validateon, ...textFieldProps } = this.props;
return (<TextField
{...textFieldProps}
onBlur={(event: any) => { this.onBlurValidation(event); }}
onChange={(event: any) => { this.onChangeValidation(event); }
}
error={validationError}
helperText={validationErrorMessage}
/>)

Related

Props "Object is possibly 'undefined'" in React Typescript

I am new to Typescript and I have an error I don't understand in React Typescript. I suspect that it comes from the way I write my interface but I am not sure.
First I call my CellEditable component
<CellEditable value={'Hello'} onChange={() => {}} />
CEllEditable has an isEditable state that toggles InputText on click
CellEditable.tsx
import React, { useState } from 'react'
import Cell from './Cell.comp'
import InputText from './InputText.comp'
interface CellEditableProps {
value: string
onChange?: () => void
}
const renderCellInput = (type: string, opts: any) => {
switch (type) {
case 'text':
return <InputText {...opts} />
default:
return <div>Missing!</div>
}
}
const CellEditable = (props: CellEditableProps) => {
const { value, onChange } = props
const [isEditing, setEditing] = useState<boolean>(false)
const handleClick = () => setEditing(!isEditing)
const handleBlur = () => setEditing(!isEditing)
const opts = {
value,
helpers: {
onBlur: handleBlur,
onChange
}
}
return (
<div onClick={handleClick}>
{
isEditing
? renderCellInput('text', opts)
: <Cell value={value} />
}
</div>
)
}
export default CellEditable
InputText.tsx
import React from 'react'
interface InputTextProps {
value?: string
helpers?: HelpersProps
}
interface HelpersProps {
onChange?: () => void
onBlur?: () => void
}
const InputText = (props: InputTextProps) => {
const { value, helpers } = props
console.log('propsInputText:', props) // Empty object in the console
return (
<input type={'text'} value={value} onChange={helpers.onChange} onBlur={helpers.onBlur} />
)
}
export default InputText
The issue is:
helpers.onChange gets this error "Object is possibly 'undefined'. TS2532"
console.log('propsInputText:', props) in InputText.tsx output an empty object.
Is it an issue with typescript and the way I write my interface?
the helpers property in InputTextProps and the onChange property in your HelpersProps are optional. either make them required by removing the question mark or assign to them a default values when destructuing.
const { value, helpers = {} } = props;
const { onChange = () => {} } = helpers;
return (
<input type={'text'} value={value} onChange={onChange} onBlur={helpers.onBlur} />
)
inside your interface:
interface CellEditableProps {
value: string
onChange?: () => void
}
you placed a ? after onChange, that tells the compiler that it can be not passed and hence you get "Object is possibly 'undefined'
To remedy this solution either you can use onChange with ! like onChange!. This thells compiler that you are sure that onChange will not be null. But this is a bad approach.
What you should do is check if it is not null or undefined and then proceed:
if(onChange) {
...do your stuff here
}
your interface declaration clearly states that these can indeed be undefined (? marks these properties as optional). You'll need to check for their existance or fill them.
const value = props.value || '';
const helpers = {
onChange: () => {},
onBlur: () => {},
...(props.helpers || {}),
};
return (
<input type={'text'} value={value} onChange={helpers.onChange} onBlur={helpers.onBlur} />
)
or similar.

React form validation hook causes infinite re-render loop

I've checked for other questions, they didn't help me
I built a React hook to validate my form inputs. However, it causes an infinite re-render loop. I've tracked down the problem to the useEffect dependency array. When I exclude the validators dependency, it works great! I won't ever change the validators during runtime, so is this prop is not needed in the dependency array? My ESLint react-hooks-plugin keeps giving me a warning that the validators dependency is missing. Please help me out. Can I leave out the validators dependency from the useEffect dependency array if I won't change it during runtime? Here is my hook and my form component:
import { useState, useEffect } from "react";
function setObjectValues<
K extends { [key: string]: unknown },
T
>(
object: K,
value: T
): { [key in keyof K]?: T } {
const initialResults: {
[key in keyof K]?: T;
} = {};
for (const key in object) {
initialResults[key] = value;
}
return initialResults;
}
export function useValidation<
K,
T extends {
[key: string]: (value: K) => boolean;
}
>(
value: K,
validators: T
): {
valid: boolean;
results: { [key in keyof T]?: boolean };
} {
const [results, setResults] = useState<
{ [key in keyof T]?: boolean }
>(setObjectValues(validators, true));
useEffect(() => {
const newResults: {
[key in keyof T]?: boolean;
} = {};
for (const key in validators) {
const valid = validators[key](value);
newResults[key] = valid;
}
setResults(newResults);
}, [value, validators]);
const valid = Object.values(results).every(
(item) => item === true
);
return { valid, results };
}
My component:
import { NextPage } from "next";
import {
useFirebase,
useValidation,
} from "app/hooks";
import {
useState,
useCallback,
FormEvent,
} from "react";
import { useRouter } from "next/router";
type InputType = "email" | "password";
const SignUp: NextPage = () => {
const firebase = useFirebase();
const router = useRouter();
const [email, setEmail] = useState("");
const {
valid: emailValid,
results: emailValidationResults,
} = useValidation(email, {
containsAt: (value) => value.includes("#"),
});
const [password, setPassword] = useState("");
const {
valid: passwordValid,
results: passwordValidationResults,
} = useValidation(password, {
isLongEnough: (value) => value.length >= 8,
containsLowerCase: (value) =>
value.toUpperCase() !== value,
containsUpperCase: (value) =>
value.toLowerCase() !== value,
containsNumber: (value) => /\d/.test(value),
});
const handleSubmit = useCallback(
(event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (
emailValid === true &&
passwordValid === true &&
email !== "" &&
password !== ""
) {
const error = firebase.createUser(
email,
password
);
if (error) {
console.warn(error.code);
} else {
router.push("/");
}
} else {
console.warn("Invalid user values");
}
},
[
email,
emailValid,
firebase,
password,
passwordValid,
router,
]
);
console.log(emailValid, passwordValid);
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input
value={email}
onChange={(event): void =>
setEmail(event.target.value)
}
id="email"
placeholder="Email"
/>
<p>{emailValid}</p>
<label htmlFor="password">Password</label>
<input
value={password}
onChange={(event): void =>
setPassword(event.target.value)
}
id="password"
placeholder="Password"
/>
<p>{passwordValid}</p>
<button type="submit">Submit</button>
</form>
);
};
export default SignUp;
const {
valid: passwordValid,
results: passwordValidationResults,
} = useValidation(password, {
isLongEnough: (value) => value.length >= 8,
containsLowerCase: (value) =>
value.toUpperCase() !== value,
containsUpperCase: (value) =>
value.toLowerCase() !== value,
containsNumber: (value) => /\d/.test(value),
});
Here, validators is actually an Object that is created during Signup render. When you create a new Object, it is always a new, different object, even though the values inside of it might be the same. This is the reason why adding it to the dependencies array causes infinite re-renders.
If the object does not depend on your component's state or props, move the declaration to outside of the component so that it is only created once.
// outside SignUp
const validators = {
isLongEnough: (value) => value.length >= 8,
containsLowerCase: (value) =>
value.toUpperCase() !== value,
containsUpperCase: (value) =>
value.toLowerCase() !== value,
containsNumber: (value) => /\d/.test(value),
};
// inside SignUp
const {
valid: passwordValid,
results: passwordValidationResults,
} = useValidation(password, validators);
I would suggest keeping validators in the dependencies array, because it should still work anyway. Leaving it out most of the time is a code smell. Most of the time, if validators changed, you will want the effect to be re-run again.

'TypeError: illegal operation attempted on a revoked proxy' when using Immer with setState

I recently refactored my React App to use Immer. However, in the onFormValueChange using produce gives me the error TypeError: illegal operation attempted on a revoked proxy while the version that is written without produce works fine.
This is the smallest I could reduce the relevant code to :
test.tsx
import { produce } from 'immer';
import { IFormValues, TestForm } from './test_form';
interface ITestProps {}
interface ITestState {
type: string;
}
export class Test extends React.Component<ITestProps, ITestState> {
constructor(props: ITestProps) {
super(props);
this.state = {
type: '',
};
}
handleSubmit = (values: IFormValues) => {
console.log.log(values);
};
onFormValueChange = (values: IFormValues) => {
this.setState(
produce((draft: ITestState) => {
draft.type = values.type;
}),
);
};
// The Following version of the function works perfectly fine and as expected:
//
// onFormValueChange = (values: IFormValues) => {
// this.setState({
// type: values.type,
// });
// };
render() {
let showField = true;
if (this.state.type === 'test') {
showField = false;
}
return (
<div>
<TestForm
submit={this.handleSubmit}
onValueChange={this.onFormValueChange}
>
<input name="type" />
</TestForm>
{showField && this.state.type}
</div>
);
}
}
test_form.tsx
import produce from 'immer';
export interface IFormValues {
[key: string]: any;
}
interface IFormProps {
submit: (values: IFormValues) => void;
onValueChange?: (values: IFormValues) => void;
}
export interface IFormState {
values: IFormValues;
}
interface IFieldProps {
value: any;
name: string;
onChange: (event: any) => void;
}
export class TestForm extends React.Component<IFormProps, IFormState> {
constructor(props: IFormProps) {
super(props);
const values: IFormValues = {};
this.state = {
values,
};
}
private handleSubmit = (event: any) => {
event.preventDefault();
const { submit } = this.props;
const { values } = this.state;
submit(values);
};
handleChange = (event: any) => {
const { name, value } = event.target;
this.setState(
produce((draft: IFormState) => {
draft.values[name] = value;
this.props.onValueChange && this.props.onValueChange(draft.values);
}),
);
};
public render() {
const { values } = this.state;
return (
<form onSubmit={this.handleSubmit} noValidate={true}>
<div>
{React.Children.map(
this.props.children,
(child: React.ReactElement<IFieldProps>) => (
<div>
{React.cloneElement(child, {
value: values[child.props.name],
onChange: this.handleChange,
})}
</div>
),
)}
<div>
<button type="submit">Submit</button>
</div>
</div>
</form>
);
}
}
Caveat: I've never used Immer. But the error is quite clear: You're trying to use a revoked Proxy. My guess is the fundamental problem is here:
this.setState(
produce((draft: IFormState) => {
draft.values[name] = value;
this.props.onValueChange && this.props.onValueChange(draft.values); // <=======
}),
);
In produce, you're passing draft.values into a function that will call produce a second time and put values.type on a different draft state. My guess is you're not allowed to pass data out of the original produce call in that way. (The documentation says "Warning: please note that the draft shouldn't be 'leaked' from the async process and stored else where. The draft will still be revoked as soon as the async process completes." but that warning is in relation to async producers, and yours aren't async. Still, it may be that it's a more general warning, it just happens to be in the async producers part.)
If so, this change to handleChange in TestForm would fix it:
this.setState(
produce((draft: IFormState) => {
draft.values[name] = value;
}),
() => {
this.props.onValueChange && this.props.onValueChange(this.state.values);
}
);
That ensures that it calls onValueChange with the value after the state has been set (presumably it's a normal object at that point, not a proxy).

display selected options in render() method in React

I am learning React and I am trying to achieve the following:
I am using Dropdown list which allows a user to select multiple items. Then I am trying to add each selected option in an array. Then I am tying to display the selected items (options) in the render method, but it is not working.
Later on I would like to convert this component into a reusable one so I can perform cascading.
So, my questions are:
1) how can I add each selected option into an array
2) iterate through the array and display items inside the render method
3) how to make this component reusable
The image below shows that the length of the array is 1, but I can't display the items. It is empty.
Below I am including the code that I have so far:
import * as React from 'react';
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import { Dropdown, IDropdown, DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import './Dropdown.Basic.Example.scss';
import { IBaseProps,BaseComponent, createRef } from 'office-ui-fabric-react';
export interface IDropdownBasicExampleProps extends IBaseProps {
loadOptions: () => Promise<IDropdownOption[]>;
onChanged: (option: IDropdownOption, index?: number) => void;
}
export interface IDropdownBasicExampleState {
selectedItem?: IDropdownOption;
selectedItems: IDropdownOption[];
loading: boolean;
options: IDropdownOption[];
selectedKey: string | number;
error: string;
}
export class DropdownBasicExample extends BaseComponent<IDropdownBasicExampleProps,IDropdownBasicExampleState> {
private _basicDropdown = createRef<IDropdown>();
private selItem:IDropdownOption;
constructor(props:IDropdownBasicExampleProps,state:IDropdownBasicExampleState) {
super(props);
this.state = {
selectedItem: undefined,
selectedItems: new Array<IDropdownOption>(),
loading: true,
error: undefined,
options: undefined,
selectedKey:""
};
}
public componentDidMount(): void {
this.loadOptions();
}
private loadOptions(): void {
this.setState({
loading: true,
error: undefined,
options: undefined
});
this.props.loadOptions()
.then((options: IDropdownOption[]): void => {
this.setState({
loading: false,
error: undefined,
options: options
});
}, (error: any): void => {
this.setState((prevState: IDropdownBasicExampleState, props: IDropdownBasicExampleProps): IDropdownBasicExampleState => {
prevState.loading = false;
prevState.error = error;
return prevState;
});
});
}
public onChangeMultiSelect = (item: IDropdownOption, index): void => {
const updatedSelectedItem = this.state.selectedItems ? this.copyArray(this.state.selectedItems) : [];
if (item.selected) {
// add the option if it's checked
updatedSelectedItem.push(item.key);
} else {
// remove the option if it's unchecked
const currIndex = updatedSelectedItem.indexOf(item.key);
if (currIndex > -1) {
updatedSelectedItem.splice(currIndex, 1);
}
}
this.setState({
selectedItems: updatedSelectedItem,
//selectedItem:item
});
if (this.props.onChanged) {
this.props.onChanged(this.state.selectedItem, index);
}
console.log(this.state.selectedItems);
};
public copyArray = (array: any[]): any[] => {
const newArray: any[] = [];
for (let i = 0; i < array.length; i++) {
newArray[i] = array[i];
}
return newArray;
};
public render() {
const { selectedItem, selectedItems } = this.state;
return (
<div className="docs-DropdownExample">
<Dropdown
placeHolder="Select options"
label="Multi-Select controlled example:"
selectedKey={selectedItem ? selectedItem.key : undefined}
//selectedKeys={selectedItems}
onChanged={this.onChangeMultiSelect}
multiSelect
options={this.state.options}
/>
<div>length: {this.state.selectedItems.length}</div>
{this.state.selectedItems.map((item:IDropdownOption)=>{
return <div>key: {item.key} {item.selected} {item.text} {item.index}</div>
})}
</div>
);
}
}
First time define a state
this.state = {
checkbox_value: []
}
then define checkboxs such as:
<input onChange = { this.checkboxValue.bind(this) } value = "0" type="checkbox" />
<input onChange = { this.checkboxValue.bind(this) } value = "2" type="checkbox" />
then use the function.
checkboxValue(event){
let checked_list = this.state.checkbox_value;
let check = event.target.checked;
let value = event.target.value;
if(check){
this.setState({
checkbox_value: [...this.state.checkbox_value, value]
});
}else{
var index = checked_list.indexOf(event.target.value);
if (index > -1){
checked_list.splice(index, 1);
}
this.setState({
checkbox_value: checked_list
})
}
}
then you can show checked value in render using map() method for checkbox_value. I hope it is usefull for you

Typescript input onchange event.target.value

In my react and typescript app, I use:
onChange={(e) => data.motto = (e.target as any).value}
How do I correctly define the typings for the class, so I wouldn't have to hack my way around the type system with any?
export interface InputProps extends React.HTMLProps<Input> {
...
}
export class Input extends React.Component<InputProps, {}> {
}
If I put target: { value: string }; I get :
ERROR in [default] /react-onsenui.d.ts:87:18
Interface 'InputProps' incorrectly extends interface 'HTMLProps<Input>'.
Types of property 'target' are incompatible.
Type '{ value: string; }' is not assignable to type 'string'.
Generally event handlers should use e.currentTarget.value, e.g.:
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
const newValue = e.currentTarget.value;
}
You can read why it so here (Revert "Make SyntheticEvent.target generic, not SyntheticEvent.currentTarget.").
UPD: As mentioned by #roger-gusmao ChangeEvent more suitable for typing form events.
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value;
}
the correct way to use in TypeScript is
handleChange(e: React.ChangeEvent<HTMLInputElement>) {
// No longer need to cast to any - hooray for react!
this.setState({temperature: e.target.value});
}
render() {
...
<input value={temperature} onChange={this.handleChange} />
...
);
}
Follow the complete class, it's better to understand:
import * as React from "react";
const scaleNames = {
c: 'Celsius',
f: 'Fahrenheit'
};
interface TemperatureState {
temperature: string;
}
interface TemperatureProps {
scale: string;
}
class TemperatureInput extends React.Component<TemperatureProps, TemperatureState> {
constructor(props: TemperatureProps) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
// handleChange(e: { target: { value: string; }; }) {
// this.setState({temperature: e.target.value});
// }
handleChange(e: React.ChangeEvent<HTMLInputElement>) {
// No longer need to cast to any - hooray for react!
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature} onChange={this.handleChange} />
</fieldset>
);
}
}
export default TemperatureInput;
You can do the following:
import { ChangeEvent } from 'react';
const onChange = (e: ChangeEvent<HTMLInputElement>)=> {
const newValue = e.target.value;
}
ChangeEvent<HTMLInputElement> is the type for change event in typescript. This is how it is done-
import { ChangeEvent } from 'react';
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
};
we can also use the onChange event fire-up with defined types(in functional component) like as follows:
const handleChange = (
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
) => {
const name = e.target.name;
const value = e.target.value;
};
as HTMLInputElement works for me
The target you tried to add in InputProps is not the same target you wanted which is in React.FormEvent
So, the solution I could come up with was, extending the event related types to add your target type, as:
interface MyEventTarget extends EventTarget {
value: string
}
interface MyFormEvent<T> extends React.FormEvent<T> {
target: MyEventTarget
}
interface InputProps extends React.HTMLProps<Input> {
onChange?: React.EventHandler<MyFormEvent<Input>>;
}
Once you have those classes, you can use your input component as
<Input onChange={e => alert(e.target.value)} />
without compile errors. In fact, you can also use the first two interfaces above for your other components.
I use something like this:
import { ChangeEvent, useState } from 'react';
export const InputChange = () => {
const [state, setState] = useState({ value: '' });
const handleChange = (event: ChangeEvent<{ value: string }>) => {
setState({ value: event?.currentTarget?.value });
}
return (
<div>
<input onChange={handleChange} />
<p>{state?.value}</p>
</div>
);
}
When using Child Component We check type like this.
Parent Component:
export default () => {
const onChangeHandler = ((e: React.ChangeEvent<HTMLInputElement>): void => {
console.log(e.currentTarget.value)
}
return (
<div>
<Input onChange={onChangeHandler} />
</div>
);
}
Child Component:
type Props = {
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
}
export Input:React.FC<Props> ({onChange}) => (
<input type="tex" onChange={onChange} />
)
An alternative that has not been mentioned yet is to type the onChange function instead of the props that it receives. Using React.ChangeEventHandler:
const stateChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
console.log(event.target.value);
};
Here is a way with ES6 object destructuring, tested with TS 3.3.
This example is for a text input.
name: string = '';
private updateName({ target }: { target: HTMLInputElement }) {
this.name = target.value;
}
This works for me also it is framework agnostic.
const handler = (evt: Event) => {
console.log((evt.target as HTMLInputElement).value))
}
This is when you're working with a FileList Object:
onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
const fileListObj: FileList | null = event.target.files;
if (Object.keys(fileListObj as Object).length > 3) {
alert('Only three images pleaseeeee :)');
} else {
// Do something
}
return;
}}
Thanks #haind
Yes HTMLInputElement worked for input field
//Example
var elem = e.currentTarget as HTMLInputElement;
elem.setAttribute('my-attribute','my value');
elem.value='5';
This HTMLInputElement is interface is inherit from HTMLElement which is inherited from EventTarget at root level. Therefore we can assert using as operator to use specific interfaces according to the context like in this case we are using HTMLInputElement for input field other interfaces can be HTMLButtonElement, HTMLImageElement etc.
For more reference you can check other available interface here
Web API interfaces by Mozilla
Interfaces in External Node Modules by Microsoft
You no need to type if you do this:
<input onChange={(event) => { setValue(e.target.value) }} />
Because if you set a new value with the arrow function directly in the html tag, typescript will understand by default the type of event.
const handleChange = (
e: ChangeEvent<HTMLInputElement>
) => {
const { name, value } = e.target;
this.setState({ ...currentState, [name]: value });
};
you can apply this on every input element in the form component
function handle_change(
evt: React.ChangeEvent<HTMLInputElement>
): string {
evt.persist(); // This is needed so you can actually get the currentTarget
const inputValue = evt.currentTarget.value;
return inputValue
}
And make sure you have "lib": ["dom"] in your tsconfig.
Convert string to number simple answer
<input
type="text"
value={incrementAmount}
onChange={(e) => {
setIncrementAmmount(+e.target.value);
}}
/>
import { NativeSyntheticEvent, TextInputChangeEventData,} from 'react-native';
// Todo in java script
const onChangeTextPassword = (text : any) => {
setPassword(text);
}
// Todo in type script use this
const onChangeTextEmail = ({ nativeEvent: { text },}: NativeSyntheticEvent<TextInputChangeEventData>) => {
console.log("________ onChangeTextEmail _________ "+ text);
setEmailId(text);
};
<TextInput
style={{ width: '100%', borderBottomWidth: 1, borderBottomColor: 'grey', height: 40, }}
autoCapitalize="none"
returnKeyType="next"
maxLength={50}
secureTextEntry={false}
onChange={onChangeTextEmail}
value={emailId}
defaultValue={emailId}
/>
const event = { target: { value: 'testing' } as HTMLInputElement };
handleChangeFunc(event as ChangeEvent<HTMLInputElement>);
this work for me.

Resources