Skip to content

Commit

Permalink
ReactKit: create class
Browse files Browse the repository at this point in the history
Summary:
This diff follows the same approach as D4418734 and in fact subsumes that diff.
Instead of processing React.createClass calls by inspecting the AST, this diff
adds a custom fun and ReactKit use type which resolves the interesting bits of
the spec one-by-one, finally resolving to a class type.

The AST traversal approach has obvious deficiencies -- we restrict ourselves to
a very limited subset of valid code.

Another significant benefit of this approach is that we can be precise about
mixins. When processing a spec, if we see a mixins object, we resolve those in
turn (recursively, as mixins can have mixins), actually mix them in, then emit
the class type.

The overall approach here collects all the resolved types into a large data
structure, where bits may be known or unknown (due to `any`, or type errors),
then flattens the mixins into a single spec, then creates the class.

Reviewed By: avikchaudhuri

Differential Revision: D4438645

fbshipit-source-id: 67f7f3dc3349a76f7ffc85a106552345a697c2b6
  • Loading branch information
samwgoldman authored and facebook-github-bot committed Feb 22, 2017
1 parent 1997ce8 commit 12741b0
Show file tree
Hide file tree
Showing 22 changed files with 1,112 additions and 336 deletions.
18 changes: 9 additions & 9 deletions lib/react.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ declare class React$PureComponent<DefaultProps, Props, State> extends React$Comp
declare class LegacyReactComponent<DefaultProps, Props, State> extends React$Component<DefaultProps, Props, State> {
// additional methods

getDefaultProps(): DefaultProps;
getInitialState(): State;



replaceState(state: State, callback?: () => void): void;

Expand All @@ -81,10 +81,10 @@ declare class LegacyReactComponent<DefaultProps, Props, State> extends React$Com
props: Props;
state: State;

static propTypes: $Subtype<{[_: $Keys<Props>]: any}>; //object whose keys are in PropTypes
static contextTypes: any;
static childContextTypes: any;
static displayName: string;




}

/**
Expand Down Expand Up @@ -169,8 +169,8 @@ declare module react {

declare function initializeTouchEvents(shouldUseTouch: boolean): void;

// compiler magic
declare function createClass(spec: any): ReactClass<any>;

declare var createClass: React$CreateClass;

declare function cloneElement<Config> (
element: React$Element<Config>,
Expand All @@ -185,7 +185,7 @@ declare module react {
* to model what happens at run time: the config are merged with the default
* props to obtain the props of a React$Element / React$Component instance.
*/
declare var createElement: React$CreateElement
declare var createElement: React$CreateElement;

// TODO: React DOM elements
declare function createFactory<Config>(
Expand Down
1 change: 1 addition & 0 deletions src/typing/codegen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ let rec gen_type t env = Type.(
| OneOfType -> "React$PropType$OneOfType"
| Shape -> "React$PropType$Shape"
) env
| CustomFunT (_, ReactCreateClass) -> add_str "React$CreateClass" env
| CustomFunT (_, ReactCreateElement) -> add_str "React$CreateElement" env
| CustomFunT (_, Merge) -> add_str "$Facebookism$Merge" env
| CustomFunT (_, MergeDeepInto) -> add_str "$Facebookism$MergeDeepInto" env
Expand Down
32 changes: 28 additions & 4 deletions src/typing/debug_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ and _json_of_t_impl json_cx t = Hh_json.(
| ObjectAssign -> "Object.assign"
| ObjectGetPrototypeOf -> "Object.getPrototypeOf"
| ReactPropType _ -> "ReactPropsCheckType"
| ReactCreateClass -> "React.createClass"
| ReactCreateElement -> "React.createElement"
| Merge -> "merge"
| MergeDeepInto -> "mergeDeepInto"
Expand Down Expand Up @@ -1419,6 +1420,7 @@ and dump_t_ (depth, tvars) cx t =
| ObjectGetPrototypeOf -> "ObjectGetPrototypeOf"
| ReactPropType p -> spf "ReactPropType (%s)" (react_prop_type p)
| ReactCreateElement -> "ReactCreateElement"
| ReactCreateClass -> "ReactCreateClass"
| Merge -> "Merge"
| MergeDeepInto -> "MergeDeepInto"
| MergeInto -> "MergeInto"
Expand Down Expand Up @@ -1585,15 +1587,18 @@ and dump_use_t_ (depth, tvars) cx t =

let react_kit =
let open React in
let resolved_object (_, pmap, _) = props pmap in
let resolve_array = function
| ResolveArray -> "ResolveArray"
| ResolveElem (todo, done_rev) ->
spf "ResolveElem (%s, %s)" (tlist todo) (tlist done_rev)
in
let resolve_object = function
| ResolveObject -> "ResolveObject"
| ResolveProp (_, k, todo, acc) ->
spf "ResolveProp (%s, %s, %s)" k (props todo) (props acc)
| ResolveDict (_, todo, acc) ->
spf "ResolveDict (%s, %s)" (props todo) (resolved_object acc)
| ResolveProp (k, todo, acc) ->
spf "ResolveProp (%s, %s, %s)" k (props todo) (resolved_object acc)
in
let simplify_prop_type = SimplifyPropType.(function
| ArrayOf -> "ArrayOf"
Expand All @@ -1603,13 +1608,32 @@ and dump_use_t_ (depth, tvars) cx t =
| OneOfType tool -> spf "OneOfType (%s)" (resolve_array tool)
| Shape tool -> spf "Shape (%s)" (resolve_object tool)
) in
let create_class = CreateClass.(
let tool = function
| Spec _ -> "Spec"
| Mixins _ -> "Mixins"
| Statics _ -> "Statics"
| PropTypes (_, tool) ->
spf "PropTypes (%s)" (resolve_object tool)
| DefaultProps _ -> "DefaultProps"
| InitialState _ -> "InitialState"
in
let knot {this; static; state_t; default_t} =
spf "{this = %s; static = %s; state = %s; default = %s}"
(kid this)
(kid static)
(kid state_t)
(kid default_t)
in
fun t k -> spf "%s, %s" (tool t) (knot k)
) in
function
| CreateElement (config, tout) ->
spf "CreateElement (%s, %s)" (kid config) (kid tout)
| ResolvePropTypes (tool, tout) ->
spf "ResolvePropTypes (%s, %s)" (resolve_object tool) (kid tout)
| SimplifyPropType (tool, tout) ->
spf "SimplifyPropType (%s, %s)" (simplify_prop_type tool) (kid tout)
| CreateClass (tool, knot, tout) ->
spf "CreateClass (%s, %s)" (create_class tool knot) (kid tout)
in

if depth = 0 then string_of_use_ctor t
Expand Down
18 changes: 16 additions & 2 deletions src/typing/flow_error.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1020,13 +1020,13 @@ let rec error_of_msg ~trace_reasons ~op ~source_file =
let expected_prop_type = "Expected a React PropType instead of" in
let resolve_object prop = function
| ResolveObject -> "Expected an object instead of"
| ResolveDict _ -> prop
| ResolveProp _ -> prop
in
let resolve_array elem = function
| ResolveArray -> "Expected an array instead of"
| ResolveElem _ -> elem
in
let resolve_prop_types = resolve_object expected_prop_type in
let simplify_prop_type = SimplifyPropType.(function
| ArrayOf -> expected_prop_type
| InstanceOf -> "Expected a class type instead of"
Expand All @@ -1035,9 +1035,23 @@ let rec error_of_msg ~trace_reasons ~op ~source_file =
| OneOfType tool -> resolve_array expected_prop_type tool
| Shape tool -> resolve_object expected_prop_type tool
) in
let create_class = CreateClass.(function
| Spec _ ->
"Expected an object instead of"
| Mixins _ ->
"`mixins` should be a tuple instead of"
| Statics _ ->
"`statics` should be an object instead of"
| PropTypes (_, tool) ->
resolve_object expected_prop_type tool
| DefaultProps _ ->
"`defaultProps` should be an object instead of"
| InitialState _ ->
"`initialState` should be an object or null instead of"
) in
let msg = match tool with
| ResolvePropTypes (tool, _) -> resolve_prop_types tool
| SimplifyPropType (tool, _) -> simplify_prop_type tool
| CreateElement _ -> "Expected React component instead of"
| CreateClass (tool, _, _) -> create_class tool
in
typecheck_error msg reasons
Loading

0 comments on commit 12741b0

Please sign in to comment.