Skip to content

Commit

Permalink
Merge pull request DefinitelyTyped#14188 from pzavolinsky/master
Browse files Browse the repository at this point in the history
React: Constrain typed changed events to inputs, selects and textareas
  • Loading branch information
johnnyreilly authored Jan 31, 2017
2 parents 08c30a2 + ec9bf7f commit 8cb9653
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 16 deletions.
40 changes: 24 additions & 16 deletions react/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ declare namespace React {
interface HTMLFactory<T extends HTMLElement> extends DOMFactory<HTMLAttributes<T>, T> {
}

interface ChangeTargetHTMLFactory<T extends HTMLElement> extends DOMFactory<ChangeTargetHTMLAttributes<T>, T> {
}

interface SVGFactory extends DOMFactory<SVGAttributes<SVGElement>, SVGElement> {
}

Expand Down Expand Up @@ -270,9 +273,10 @@ declare namespace React {
//
// Event System
// ----------------------------------------------------------------------
interface SyntheticEventBase<CURRENT, TARGET> {

interface SyntheticEvent<T> {
bubbles: boolean;
currentTarget: EventTarget & CURRENT;
currentTarget: EventTarget & T;
cancelable: boolean;
defaultPrevented: boolean;
eventPhase: number;
Expand All @@ -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<T> extends SyntheticEventBase<T, EventTarget> {
// If you thought target should be `EventTarget & T`,
// see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239
}

interface ClipboardEvent<T> extends SyntheticEvent<T> {
clipboardData: DataTransfer;
}
Expand All @@ -312,7 +312,8 @@ declare namespace React {
interface FormEvent<T> extends SyntheticEvent<T> {
}

interface ChangeEvent<T> extends SyntheticEventBase<T, T> {
interface ChangeEvent<T> extends SyntheticEvent<T> {
target: EventTarget & T;
}

interface KeyboardEvent<T> extends SyntheticEvent<T> {
Expand Down Expand Up @@ -433,6 +434,9 @@ declare namespace React {
interface HTMLProps<T> extends HTMLAttributes<T>, ClassAttributes<T> {
}

interface ChangeTargetHTMLProps<T extends HTMLElement> extends ChangeTargetHTMLAttributes<T>, ClassAttributes<T> {
}

interface SVGProps extends SVGAttributes<SVGElement>, ClassAttributes<SVGElement> {
}

Expand Down Expand Up @@ -465,7 +469,7 @@ declare namespace React {
onBlurCapture?: FocusEventHandler<T>;

// Form Events
onChange?: ChangeEventHandler<T>;
onChange?: FormEventHandler<T>;
onChangeCapture?: FormEventHandler<T>;
onInput?: FormEventHandler<T>;
onInputCapture?: FormEventHandler<T>;
Expand Down Expand Up @@ -2149,6 +2153,10 @@ declare namespace React {
unselectable?: boolean;
}

interface ChangeTargetHTMLAttributes<T extends HTMLElement> extends HTMLAttributes<T> {
onChange?: ChangeEventHandler<T>;
}

// 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
Expand Down Expand Up @@ -2459,7 +2467,7 @@ declare namespace React {
i: HTMLFactory<HTMLElement>;
iframe: HTMLFactory<HTMLIFrameElement>;
img: HTMLFactory<HTMLImageElement>;
input: HTMLFactory<HTMLInputElement>;
input: ChangeTargetHTMLFactory<HTMLInputElement>;
ins: HTMLFactory<HTMLModElement>;
kbd: HTMLFactory<HTMLElement>;
keygen: HTMLFactory<HTMLElement>;
Expand Down Expand Up @@ -2494,7 +2502,7 @@ declare namespace React {
samp: HTMLFactory<HTMLElement>;
script: HTMLFactory<HTMLElement>;
section: HTMLFactory<HTMLElement>;
select: HTMLFactory<HTMLSelectElement>;
select: ChangeTargetHTMLFactory<HTMLSelectElement>;
small: HTMLFactory<HTMLElement>;
source: HTMLFactory<HTMLSourceElement>;
span: HTMLFactory<HTMLSpanElement>;
Expand All @@ -2506,7 +2514,7 @@ declare namespace React {
table: HTMLFactory<HTMLTableElement>;
tbody: HTMLFactory<HTMLTableSectionElement>;
td: HTMLFactory<HTMLTableDataCellElement>;
textarea: HTMLFactory<HTMLTextAreaElement>;
textarea: ChangeTargetHTMLFactory<HTMLTextAreaElement>;
tfoot: HTMLFactory<HTMLTableSectionElement>;
th: HTMLFactory<HTMLTableHeaderCellElement>;
thead: HTMLFactory<HTMLTableSectionElement>;
Expand Down Expand Up @@ -2686,7 +2694,7 @@ declare global {
i: React.HTMLProps<HTMLElement>;
iframe: React.HTMLProps<HTMLIFrameElement>;
img: React.HTMLProps<HTMLImageElement>;
input: React.HTMLProps<HTMLInputElement>;
input: React.ChangeTargetHTMLProps<HTMLInputElement>;
ins: React.HTMLProps<HTMLModElement>;
kbd: React.HTMLProps<HTMLElement>;
keygen: React.HTMLProps<HTMLElement>;
Expand Down Expand Up @@ -2722,7 +2730,7 @@ declare global {
samp: React.HTMLProps<HTMLElement>;
script: React.HTMLProps<HTMLElement>;
section: React.HTMLProps<HTMLElement>;
select: React.HTMLProps<HTMLSelectElement>;
select: React.ChangeTargetHTMLProps<HTMLSelectElement>;
small: React.HTMLProps<HTMLElement>;
source: React.HTMLProps<HTMLSourceElement>;
span: React.HTMLProps<HTMLSpanElement>;
Expand All @@ -2734,7 +2742,7 @@ declare global {
table: React.HTMLProps<HTMLTableElement>;
tbody: React.HTMLProps<HTMLTableSectionElement>;
td: React.HTMLProps<HTMLTableDataCellElement>;
textarea: React.HTMLProps<HTMLTextAreaElement>;
textarea: React.ChangeTargetHTMLProps<HTMLTextAreaElement>;
tfoot: React.HTMLProps<HTMLTableSectionElement>;
th: React.HTMLProps<HTMLTableHeaderCellElement>;
thead: React.HTMLProps<HTMLTableSectionElement>;
Expand Down
15 changes: 15 additions & 0 deletions react/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLInputElement>;
type InputFormEvent = React.FormEvent<HTMLInputElement>;
const changeEvent:InputChangeEvent = undefined as any;
const formEvent:InputFormEvent = changeEvent;

0 comments on commit 8cb9653

Please sign in to comment.