Skip to content

Commit

Permalink
constructor annots
Browse files Browse the repository at this point in the history
Summary: It was not really possible to annotate ES3 functions that act like ES6 classes.
This diff implements some functionality that provides a way to do that.

Reviewed By: @jeffmo

Differential Revision: D2152762
  • Loading branch information
avikchaudhuri authored and facebook-github-bot-4 committed Jun 16, 2015
1 parent c0d352d commit 618186a
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 15 deletions.
5 changes: 3 additions & 2 deletions src/dts/tests/classes/declarations/classes.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
declare class C {
x: number;

}
declare class D extends C {
y: string;

}

3 changes: 2 additions & 1 deletion src/dts/tests/enums/declarations/enums.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ declare class Color {
static R : number;
static G : number;
static B : number;

}

3 changes: 2 additions & 1 deletion src/dts/tests/modules/declarations/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ declare module M {
declare var x: number;
declare class C {
y: typeof x;

}
}

3 changes: 2 additions & 1 deletion src/dts/tests/nested_modules/declarations/nested_modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ declare module M {
declare var x: number;
declare class C {
y: typeof x;

}
declare var m: typeof N.z;
}
Expand All @@ -18,3 +18,4 @@ declare module P {
declare var M: $Exports<'M'>;
declare var a: typeof M.N.z;
}

33 changes: 23 additions & 10 deletions src/typing/flow_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2626,16 +2626,29 @@ let rec __flow cx (l, u) trace =
rec_flow cx trace (instance, GetT(reason,"statics",tvar));
rec_flow cx trace (tvar,u)

(********)
(* cast *)
(********)

| (ClassT instance, (FunT _ | CallT _))
->
let reason = reason_of_t u in
let tvar = mk_tvar cx reason in
rec_flow cx trace (instance, GetT(reason,"statics",tvar));
rec_flow cx trace (tvar, GetT(reason,"$call",u))
(***************************************************************************)
(* classes can behave like functions, functions can be declared as classes *)
(***************************************************************************)

(* When a class value flows to a function annotation or call site, check for
the presence of a $call property in the former (as a static) compatible
with the latter. *)
| (ClassT instance, (FunT (reason, _, _, _) | CallT (reason, _))) ->
rec_flow cx trace (l, GetT(reason,"$call",u))

(* For a function type to be used as a class type, the following must hold:
- the class's instance type must be a subtype of the function's prototype
property type and 'this' type
- the function's statics should be included in the class's statics
(typically a function's statics are under-specified, so we don't
enforce equality)
- the class's static $call property type must be a subtype of the
function type. *)
| (FunT (reason, static, prototype, funtype), ClassT instance) ->
rec_flow cx trace (instance, prototype);
rec_flow cx trace (instance, funtype.this_t);
rec_flow cx trace (instance, GetT(reason,"statics",static));
rec_flow cx trace (u, GetT(reason,"$call",l))

(************)
(* indexing *)
Expand Down
Empty file.
46 changes: 46 additions & 0 deletions tests/constructor_annots/constructor_annots.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

constructors.js:2:1,4:1: property m
Property not found in
constructors.js:18:28,31: IFoo

constructors.js:3:3,12: assignment of property x
Error:
constructors.js:3:12,12: number
This type is incompatible with
constructors.js:14:6,12: boolean

constructors.js:3:12,12: number
This type is incompatible with
test.js:2:8,13: string

constructors.js:5:9,9: number
This type is incompatible with
constructors.js:16:13,19: boolean

constructors.js:16:13,19: boolean
This type is incompatible with
test.js:3:8,13: string

test.js:4:17,29: call of method m
Error:
constructors.js:6:32,32: number
This type is incompatible with
test.js:4:8,13: string

test.js:7:18,29: property x
Error:
constructors.js:14:6,12: boolean
This type is incompatible with
test.js:7:9,14: string

test.js:8:18,23: property y
Error:
constructors.js:16:13,19: boolean
This type is incompatible with
test.js:8:9,14: string

test.js:9:18,31: call of method m
Property not found in
constructors.js:18:28,31: IFoo

Found 9 errors
18 changes: 18 additions & 0 deletions tests/constructor_annots/constructors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Foo is a class-like function
function Foo() {
this.x = 0; // constructs objects with property x
}
Foo.y = 0; // has static property y
Foo.prototype = { m() { return 0; } };

// exporting Foo directly often works
exports.Foo = Foo;

// but sometimes, you want to type Foo
// you could declare Foo as a class
declare class IFoo {
x: boolean; // error, should have declared x: number instead
static (): void;
static y: boolean; // error, should have declared static y: number instead
}
exports.Foo2 = (Foo: Class<IFoo>);
9 changes: 9 additions & 0 deletions tests/constructor_annots/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var Foo = require('./constructors').Foo;
var x: string = new Foo().x; // error, found number instead of string
var y: string = Foo.y; // error, found number instead of string
var z: string = new Foo().m();

var Foo2 = require('./constructors').Foo2;
var x2: string = new Foo2().x; // error, found boolean instead of string
var y2: string = Foo2.y; // error, found boolean instead of string
var z2: string = new Foo2().m();

0 comments on commit 618186a

Please sign in to comment.