version: v1-beta12
as per TextField.d.ts
in v1-beta12, the typings extend FormControlProps
.
This in turn extends React.HtmlHTMLAttributes<HTMLDivElement>
, which eventually has property onChange(ev :
React.SyntheticEvent<HTMLDivElement>
)
.
The problem being that React.SyntheticEvent<HTMLDivElement>
is generically typed to HTMLDivElement
, even though in v1-beta12, the event's currentTarget
is actually an HTMLInputElement
.
It would make the typings much easier to use if this was fixed.
The problem is that with the generic set to HTMLDivElement
, onChange event handlers must be coded like so:
function onChange(ev : React.FormEvent<HTMLDivElement>) {
const actualTarget = ev.currentTarget as any as HTMLInputElement
console.log(actualTarget.value)
}
// or without the any...
function onChange(ev : React.FormEvent<HTMLElement>) {
const actualTarget = ev.currentTarget as HTMLInputElement
console.log(actualTarget.value)
}
Can you please add an usage example.
From looking at the implementation of TextField
inheriting from a div
is correct. If you put an onChange
on the TextField
it will be passed to the FormControl
, which is by default rendered as a div
. So, It's kinda weird that the currentTarget
is an input.
If you want to listen for changes on the input field, you can use the InputProps
.
Whilst TextField
returns a FormControl
around the Input
component, it doesn't attach the onChange
event to the FormControl
:
https://github.com/callemall/material-ui/blob/dbbcaa6e1a6ae05b87b076091985ec6e2ac97a3d/src/TextField/TextField.js#L178-L188
It attaches it to the Input
component:
https://github.com/callemall/material-ui/blob/dbbcaa6e1a6ae05b87b076091985ec6e2ac97a3d/src/TextField/TextField.js#L205-L223
So whilst TextField
technically is by default rooted with a div
, the component you're attaching the event to is (by default) an input
.
Proper React dictates that you should use the currentTarget
on the event to interact with the event, NOT the target
(which is why react's SyntheticEvent
typings provides a useless type for target
).
How can I get the value
from a HTMLDivElement
?
If that's your intention from an API design perspective, then you should probably provide custom events that explicitly expose the value, so consumers don't have to fight with your definitions.
My bad, you're correct. The onChange is set on the <Input>
. Updated the typings accordingly.
Regarding your issue with the "API design perspective". This is OSS, so anyone is welcome to contribute ;) The people doing the TS typings are doing their best to make everyone happy.
You were a version out - in v11 it put it on the FormControl
, it was changed 2 days ago (released with v12): https://github.com/callemall/material-ui/commit/b815af0d644493e85cff96644573709dc9f534f0
It's on my todo list to contribute back to this and a few other projects we're leaning on. After my current slab of work slows down.
The latest fix (I'm using 1.0.0-beta.16
) prevents compilation with a type error.
This code
class TextInputDemo ... {
...
render() {
return (
<TextField
label="Text"
value={this.state.title}
onChange={this.handleChange}
/>
);
}
private handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
...
}
}
fails with the following compiler type error:
error TS2322: Type '{ label: "Text"; value: string; onChange: (event: ChangeEvent<HTMLInputElement>) => void; requir...' is not assignable to type 'IntrinsicAttributes & { autoComplete?: string | undefined; autoFocus?: boolean | undefined; child...'.
Type '{ label: "Text"; value: string; onChange: (event: ChangeEvent<HTMLInputElement>) => void; requir...' is not assignable to type 'FormControlProps'.
Types of property 'onChange' are incompatible.
Type '(event: ChangeEvent<HTMLInputElement>) => void' is not assignable to type '((event: FormEvent<HTMLDivElement>) => void) | undefined'.
Type '(event: ChangeEvent<HTMLInputElement>) => void' is not assignable to type '(event: FormEvent<HTMLDivElement>) => void'.
If I change the event handler to
private handleChange = (event: React.FormEvent<HTMLDivElement>) => {
...
}
````
I get the following compiler error:
...
Types of property 'onChange' are incompatible.
Type '(event: FormEvent
Type '(event: FormEvent
The only workaround at the moment is something like this:
```typescript
private handleChange = (event: {}) => {
const e = event as React.ChangeEvent<HTMLInputElement>;
...
}
The problem lies in the typedefinition of the TextFieldProps
:
export type TextFieldProps = {
...
onChange?: React.ChangeEventHandler<HTMLInputElement>;
} & FormControlProps;
FormControlProps
extends React.HtmlHTMLAttributes<HTMLDivElement>
and somewhere deeper in the hierarchy of FormControlProps
we find the following interface:
interface DOMAttributes<T> {
...
// Form Events
onChange?: FormEventHandler<T>;
...
}
And as T
is of type HTMLDivElement
here, we cause the conflict which makes the compiler fail.
@svenwiegand This was already fixed in #8618
@sebald Yeah thanks. Can confirm that this is working with 1.0.0-beta.17
.
Most helpful comment
The latest fix (I'm using
1.0.0-beta.16
) prevents compilation with a type error.This code
fails with the following compiler type error:
If I change the event handler to
...) => void' is not assignable to type '((event: ChangeEvent) => void) | undefined'.) => void' is not assignable to type '(event: ChangeEvent) => void'.
Types of property 'onChange' are incompatible.
Type '(event: FormEvent
Type '(event: FormEvent
The problem lies in the typedefinition of the
TextFieldProps
:FormControlProps
extendsReact.HtmlHTMLAttributes<HTMLDivElement>
and somewhere deeper in the hierarchy ofFormControlProps
we find the following interface:And as
T
is of typeHTMLDivElement
here, we cause the conflict which makes the compiler fail.