From ec9bf7f22990ed5c3d419356e263f595bef7eebb Mon Sep 17 00:00:00 2001 From: Patricio Zavolinsky Date: Mon, 23 Jan 2017 10:48:46 +0000 Subject: [PATCH] React: Constrain typed changed events to inputs, selects and textareas --- react/index.d.ts | 40 ++++++++++++++++++++++++---------------- react/test/index.ts | 15 +++++++++++++++ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/react/index.d.ts b/react/index.d.ts index 61aa81ab01..f25e5c0afd 100644 --- a/react/index.d.ts +++ b/react/index.d.ts @@ -81,6 +81,9 @@ declare namespace React { interface HTMLFactory extends DOMFactory, T> { } + interface ChangeTargetHTMLFactory extends DOMFactory, T> { + } + interface SVGFactory extends DOMFactory, SVGElement> { } @@ -270,9 +273,10 @@ declare namespace React { // // Event System // ---------------------------------------------------------------------- - interface SyntheticEventBase { + + interface SyntheticEvent { bubbles: boolean; - currentTarget: EventTarget & CURRENT; + currentTarget: EventTarget & T; cancelable: boolean; defaultPrevented: boolean; eventPhase: number; @@ -283,16 +287,12 @@ declare namespace React { stopPropagation(): void; isPropagationStopped(): boolean; persist(): void; - target: EventTarget & TARGET; + // If you thought this should be `EventTarget & T`, see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 + target: EventTarget; timeStamp: Date; type: string; } - interface SyntheticEvent extends SyntheticEventBase { - // If you thought target should be `EventTarget & T`, - // see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 - } - interface ClipboardEvent extends SyntheticEvent { clipboardData: DataTransfer; } @@ -312,7 +312,8 @@ declare namespace React { interface FormEvent extends SyntheticEvent { } - interface ChangeEvent extends SyntheticEventBase { + interface ChangeEvent extends SyntheticEvent { + target: EventTarget & T; } interface KeyboardEvent extends SyntheticEvent { @@ -433,6 +434,9 @@ declare namespace React { interface HTMLProps extends HTMLAttributes, ClassAttributes { } + interface ChangeTargetHTMLProps extends ChangeTargetHTMLAttributes, ClassAttributes { + } + interface SVGProps extends SVGAttributes, ClassAttributes { } @@ -465,7 +469,7 @@ declare namespace React { onBlurCapture?: FocusEventHandler; // Form Events - onChange?: ChangeEventHandler; + onChange?: FormEventHandler; onChangeCapture?: FormEventHandler; onInput?: FormEventHandler; onInputCapture?: FormEventHandler; @@ -2149,6 +2153,10 @@ declare namespace React { unselectable?: boolean; } + interface ChangeTargetHTMLAttributes extends HTMLAttributes { + onChange?: ChangeEventHandler; + } + // this list is "complete" in that it contains every SVG attribute // that React supports, but the types can be improved. // Full list here: https://facebook.github.io/react/docs/dom-elements.html @@ -2459,7 +2467,7 @@ declare namespace React { i: HTMLFactory; iframe: HTMLFactory; img: HTMLFactory; - input: HTMLFactory; + input: ChangeTargetHTMLFactory; ins: HTMLFactory; kbd: HTMLFactory; keygen: HTMLFactory; @@ -2494,7 +2502,7 @@ declare namespace React { samp: HTMLFactory; script: HTMLFactory; section: HTMLFactory; - select: HTMLFactory; + select: ChangeTargetHTMLFactory; small: HTMLFactory; source: HTMLFactory; span: HTMLFactory; @@ -2506,7 +2514,7 @@ declare namespace React { table: HTMLFactory; tbody: HTMLFactory; td: HTMLFactory; - textarea: HTMLFactory; + textarea: ChangeTargetHTMLFactory; tfoot: HTMLFactory; th: HTMLFactory; thead: HTMLFactory; @@ -2686,7 +2694,7 @@ declare global { i: React.HTMLProps; iframe: React.HTMLProps; img: React.HTMLProps; - input: React.HTMLProps; + input: React.ChangeTargetHTMLProps; ins: React.HTMLProps; kbd: React.HTMLProps; keygen: React.HTMLProps; @@ -2722,7 +2730,7 @@ declare global { samp: React.HTMLProps; script: React.HTMLProps; section: React.HTMLProps; - select: React.HTMLProps; + select: React.ChangeTargetHTMLProps; small: React.HTMLProps; source: React.HTMLProps; span: React.HTMLProps; @@ -2734,7 +2742,7 @@ declare global { table: React.HTMLProps; tbody: React.HTMLProps; td: React.HTMLProps; - textarea: React.HTMLProps; + textarea: React.ChangeTargetHTMLProps; tfoot: React.HTMLProps; th: React.HTMLProps; thead: React.HTMLProps; diff --git a/react/test/index.ts b/react/test/index.ts index b575055514..38ad574aa4 100644 --- a/react/test/index.ts +++ b/react/test/index.ts @@ -674,3 +674,18 @@ class SyntheticEventTargetValue extends React.Component<{}, { value: string }> { }); } } + +React.DOM.input({ + onChange: event => { + // `event.target` is guaranteed to be HTMLInputElement + event.target.value; + } +}); + +// A ChangeEvent is a valid FormEvent (maintain compatibility with existing +// event handlers) + +type InputChangeEvent = React.ChangeEvent; +type InputFormEvent = React.FormEvent; +const changeEvent:InputChangeEvent = undefined as any; +const formEvent:InputFormEvent = changeEvent;