Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add enhanced typings #1287

Merged
merged 8 commits into from
Mar 17, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/inferno-compat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { cloneVNode } from 'inferno-clone-vnode';
import { ClassicComponentClass, ComponentSpec, createClass } from 'inferno-create-class';
import { createElement } from 'inferno-create-element';
import { isArray, isBrowser, isFunction, isInvalid, isNull, isNullOrUndef, isString, NO_OP } from 'inferno-shared';
import { VNodeFlags} from 'inferno-vnode-flags';
import { VNodeFlags } from 'inferno-vnode-flags';
import { isValidElement } from './isValidElement';
import PropTypes from './PropTypes';
import { SVGDOMPropertyConfig } from './SVGDOMPropertyConfig';
Expand Down Expand Up @@ -275,7 +275,7 @@ class PureComponent<P, S> extends Component<P, S> {
class WrapperComponent<P, S> extends Component<P, S> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can neaten this up by having

interface ContextProps {
    context: any;
}

type WrappedComponentProps<OriginalProps> = OriginalProps | ContextProps

class WrappedComponent<P, S> extends Component<WrappedComponentProps<P>, S> {

public getChildContext() {
// tslint:disable-next-line
return this.props.context;
return (this.props as any).context;
}

public render(props) {
Expand Down
4 changes: 2 additions & 2 deletions packages/inferno-create-element/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function createElement<T>(type: string | Function | Component<any, any>,
let children: any = _children;
let ref: any = null;
let key = null;
let className = null;
let className: string | null = null;
let flags = 0;
let newProps;

Expand All @@ -44,7 +44,7 @@ export function createElement<T>(type: string | Function | Component<any, any>,

for (const prop in props) {
if (prop === 'className' || prop === 'class') {
className = props[prop];
className = (props as any)[prop];
} else if (prop === 'key') {
key = props.key;
} else if (prop === 'children' && isUndefined(children)) {
Expand Down
6 changes: 3 additions & 3 deletions packages/inferno-router/src/Link.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { linkEvent, createVNode, VNode } from 'inferno';
import { linkEvent, createVNode, VNode, MouseEvent } from 'inferno';
import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags';
import { invariant } from './utils';

const isModifiedEvent = (event): boolean => Boolean(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
const isModifiedEvent = (event: MouseEvent<any>): boolean => Boolean(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);

export interface ILinkProps {
children: any;
Expand All @@ -14,7 +14,7 @@ export interface ILinkProps {
innerRef: any;
}

function handleClick({ props, context }, event) {
function handleClick({ props, context }, event: MouseEvent<any>) {
if (props.onClick) {
props.onClick(event);
}
Expand Down
51 changes: 33 additions & 18 deletions packages/inferno-router/src/Route.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
import { Component, createComponentVNode, VNode } from 'inferno';
import { Component, ComponentType, createComponentVNode, InfernoChildren, VNode } from 'inferno';
import { VNodeFlags } from 'inferno-vnode-flags';
import { Children, invariant, warning } from './utils';
import { matchPath } from './matchPath';
import * as H from 'history';

const isEmptyChildren = children => Children.count(children) === 0;

export interface Match<P> {
params: P;
isExact: boolean;
path: string;
url: string;
}

export interface RouteComponentProps<P> {
match: Match<P>;
location: H.Location;
history: H.History;
staticContext?: any;
}

export interface IRouteProps {
computedMatch: any; // private, from <Switch>
path: any;
exact: any;
strict: any;
sensitive: any;
component: any;
render: any;
location: any;
children: Array<Component<any, any>>;
computedMatch?: any; // private, from <Switch>
path?: string;
exact?: boolean;
strict?: boolean;
sensitive?: boolean;
component?: ComponentType<RouteComponentProps<any>> | ComponentType<any>;
render?: ((props: RouteComponentProps<any>) => VNode);
location?: H.Location;
children: ((props: RouteComponentProps<any>) => VNode) | InfernoChildren;
}

/**
Expand All @@ -40,18 +55,18 @@ class Route extends Component<IRouteProps, any> {
};
}

public computeMatch({ computedMatch, location, path, strict, exact, sensitive }, router) {
public computeMatch({computedMatch, location, path, strict, exact, sensitive}, router) {
if (computedMatch) {
// <Switch> already computed the match for us
return computedMatch;
}

invariant(router, 'You should not use <Route> or withRouter() outside a <Router>');

const { route } = router;
const {route} = router;
const pathname = (location || route.location).pathname;

return path ? matchPath(pathname, { path, strict, exact, sensitive }) : route.match;
return path ? matchPath(pathname, {path, strict, exact, sensitive}) : route.match;
}

public componentWillReceiveProps(nextProps, nextContext) {
Expand All @@ -73,11 +88,11 @@ class Route extends Component<IRouteProps, any> {
}

public render(): VNode | null {
const { match } = this.state;
const { children, component, render } = this.props;
const { history, route, staticContext } = this.context.router;
const {match} = this.state;
const {children, component, render} = this.props;
const {history, route, staticContext} = this.context.router;
const location = this.props.location || route.location;
const props = { match, location, history, staticContext };
const props = {match, location, history, staticContext};

if (component) {
return match ? createComponentVNode(VNodeFlags.ComponentUnknown, component, props) : null;
Expand All @@ -100,7 +115,7 @@ class Route extends Component<IRouteProps, any> {
}

if (process.env.NODE_ENV !== 'production') {
Route.prototype.componentWillMount = function() {
Route.prototype.componentWillMount = function () {
warning(
!(this.props.component && this.props.render),
'You should not use <Route component> and <Route render> in the same route; <Route render> will be ignored'
Expand Down
5 changes: 3 additions & 2 deletions packages/inferno-router/src/Switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { Component, createComponentVNode, VNode } from 'inferno';
import { matchPath } from './matchPath';
import { Children, invariant, isValidElement, warning } from './utils';
import { combineFrom } from 'inferno-shared';
import { IRouteProps } from "./Route";

export interface ISwitchProps {
export interface ISwitchProps extends IRouteProps {
router: any;
children: Array<Component<any, any>>;
// children: Array<Component<any, any>>;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions packages/inferno-router/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function invariant(condition, format, a?, b?, c?, d?, e?, f?) {
const ARR = [];

export const Children = {
forEach(children: any[], fn: Function): void {
forEach(children: any, fn: Function): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typing seems to be more correct with any[] as before?

if (isNullOrUndef(children)) {
return;
}
Expand All @@ -52,19 +52,19 @@ export const Children = {
}
},

count(children: any[]): number {
count(children: any): number {
return Children.toArray(children).length;
},

only(children: any[]): any {
only(children: any): any {
children = Children.toArray(children);
if (children.length !== 1) {
throw new Error('Children.only() expects only one child.');
}
return children[0];
},

toArray(children: any[]): any[] {
toArray(children: any): any[] {
return isNullOrUndef(children) ? [] : isArray(children) ? children : ARR.concat(children);
}
};
2 changes: 1 addition & 1 deletion packages/inferno-router/src/withRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function withRouter(Com) {
const C: any = function(props: IWithRouterProps) {
const { wrappedComponentRef, ...remainingProps } = props;

return createComponentVNode(VNodeFlags.ComponentClass, Route, {
return createComponentVNode<any>(VNodeFlags.ComponentClass, Route, {
render(routeComponentProps) {
return createComponentVNode(
VNodeFlags.ComponentUnknown,
Expand Down
3 changes: 2 additions & 1 deletion packages/inferno/src/DOM/events/delegation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isNull } from 'inferno-shared';
import { SemiSyntheticEvent } from "inferno";

const attachedEventCounts = {};
const attachedEvents = {};
Expand Down Expand Up @@ -32,7 +33,7 @@ export function handleEvent(name: string, nextEvent: Function | null, dom) {
}
}

function dispatchEvents(event, target, isClick: boolean, name: string, eventData: IEventData) {
function dispatchEvents(event: SemiSyntheticEvent<any>, target, isClick: boolean, name: string, eventData: IEventData) {
let dom = target;
while (!isNull(dom)) {
// Html Nodes can be nested fe: span inside button in that scenario browser does not handle disabled attribute on parent,
Expand Down
61 changes: 61 additions & 0 deletions packages/inferno/src/DOM/events/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// Event System
// ----------------------------------------------------------------------

import {
NativeAnimationEvent, NativeClipboardEvent, NativeCompositionEvent, NativeDragEvent, NativeFocusEvent,
NativeKeyboardEvent,
NativeMouseEvent, NativeTouchEvent, NativeTransitionEvent, NativeUIEvent, NativeWheelEvent
} from "../../JSX";
import { LinkedEvent } from "./linkEvent";

export interface SemiSyntheticEvent<T> extends Event {
/**
* A reference to the element on which the event listener is registered.
*/
currentTarget: EventTarget & T;
}

export type ClipboardEvent<T> = SemiSyntheticEvent<T> & NativeClipboardEvent;
export type CompositionEvent<T> = SemiSyntheticEvent<T> & NativeCompositionEvent;
export type DragEvent<T> = MouseEvent<T> & NativeDragEvent;
export type FocusEvent<T> = SemiSyntheticEvent<T> & NativeFocusEvent;
export type FormEvent<T> = SemiSyntheticEvent<T>;

export interface InvalidEvent<T> extends SemiSyntheticEvent<T> {
target: EventTarget & T;
}

export interface ChangeEvent<T> extends SemiSyntheticEvent<T> {
target: EventTarget & T;
}

export type KeyboardEvent<T> = SemiSyntheticEvent<T> & NativeKeyboardEvent;
export type MouseEvent<T> = SemiSyntheticEvent<T> & NativeMouseEvent;
export type TouchEvent<T> = SemiSyntheticEvent<T> & NativeTouchEvent;
export type UIEvent<T> = SemiSyntheticEvent<T> & NativeUIEvent;
export type WheelEvent<T> = MouseEvent<T> & NativeWheelEvent;
export type AnimationEvent<T> = SemiSyntheticEvent<T> & NativeAnimationEvent;
export type TransitionEvent<T> = SemiSyntheticEvent<T> & NativeTransitionEvent;

//
// Event Handler Types
// ----------------------------------------------------------------------

export type EventHandler<E extends SemiSyntheticEvent<any>> = { bivarianceHack(event: E): void }["bivarianceHack"] | LinkedEvent<any, E>;

export type InfernoEventHandler<T> = EventHandler<SemiSyntheticEvent<T>>;

export type ClipboardEventHandler<T> = EventHandler<ClipboardEvent<T>>;
export type CompositionEventHandler<T> = EventHandler<CompositionEvent<T>>;
export type DragEventHandler<T> = EventHandler<DragEvent<T>>;
export type FocusEventHandler<T> = EventHandler<FocusEvent<T>>;
export type FormEventHandler<T> = EventHandler<FormEvent<T>>;
export type ChangeEventHandler<T> = EventHandler<ChangeEvent<T>>;
export type KeyboardEventHandler<T> = EventHandler<KeyboardEvent<T>>;
export type MouseEventHandler<T> = EventHandler<MouseEvent<T>>;
export type TouchEventHandler<T> = EventHandler<TouchEvent<T>>;
export type UIEventHandler<T> = EventHandler<UIEvent<T>>;
export type WheelEventHandler<T> = EventHandler<WheelEvent<T>>;
export type AnimationEventHandler<T> = EventHandler<AnimationEvent<T>>;
export type TransitionEventHandler<T> = EventHandler<TransitionEvent<T>>;
7 changes: 6 additions & 1 deletion packages/inferno/src/DOM/events/linkEvent.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { isFunction } from 'inferno-shared';

export interface LinkedEvent<T, E extends Event> {
data: T;
event: (data: T, event: E) => void;
}

/**
* Links given data to event as first parameter
* @param {*} data data to be linked, it will be available in function as first parameter
* @param {Function} event Function to be called when event occurs
* @returns {{data: *, event: Function}}
*/
export function linkEvent(data, event) {
export function linkEvent<T, E extends Event>(data: T, event: (data: T, event: E) => void): LinkedEvent<T, E> | null {
if (isFunction(event)) {
return { data, event };
}
Expand Down
Loading