Skip to content

Commit

Permalink
make $Values on a frozen object return singleton literals
Browse files Browse the repository at this point in the history
Summary:
on a frozen object, StrT, NumT and BoolT values can't be changed so we
can treat them as singletons. this makes this pattern work:

```
const Enum = Object.freeze({
  X: 'x',
  Y: 'y',
});
type EnumT = $Values<typeof Enum>
('a': EnumT); // error instead of StrT ~> StrT
```

Reviewed By: avikchaudhuri

Differential Revision: D6232529

fbshipit-source-id: d24339d7a7a607e24a9312d637f83d5c92a97a15
  • Loading branch information
mroch authored and facebook-github-bot committed Nov 9, 2017
1 parent 42ba05d commit 7c3390f
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 3 deletions.
18 changes: 16 additions & 2 deletions src/typing/flow_js.ml
Expand Up @@ -2801,15 +2801,29 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace =
(* values *)
(**********)

| DefT (_, ObjT { props_tmap = tmap; dict_t; _ }), GetValuesT (reason, values) ->
| DefT (_, ObjT { props_tmap = tmap; dict_t; flags; _ }), GetValuesT (reason, values) ->
(* Find all of the props. *)
let props = Context.find_props cx tmap in
(* Get the read type for all readable properties and discard the rest. *)
let ts = SMap.fold (fun key prop ts ->
match Property.read_t prop with
(* Don't include the type for the internal "$call" property if one
exists. *)
| Some t when key != "$call" -> t :: ts
| Some t when key != "$call" ->
let t = if flags.frozen then
match t with
| DefT (t_reason, StrT (Literal (_, lit))) ->
let t_reason = replace_reason_const (RStringLit lit) t_reason in
DefT (t_reason, SingletonStrT lit)
| DefT (t_reason, NumT (Literal (_, lit))) ->
let t_reason = replace_reason_const (RNumberLit (snd lit)) t_reason in
DefT (t_reason, SingletonNumT lit)
| DefT (t_reason, BoolT (Some lit)) ->
let t_reason = replace_reason_const (RBooleanLit lit) t_reason in
DefT (t_reason, SingletonBoolT lit)
| _ -> t
else t in
t :: ts
| _ -> ts
) props [] in
(* If the object has a dictionary value then add that to our types. *)
Expand Down
1 change: 1 addition & 0 deletions tests/values/.flowconfig
@@ -1,2 +1,3 @@
[options]
unsafe.enable_getters_and_setters=true
no_flowlib=false
15 changes: 15 additions & 0 deletions tests/values/object_types.js
Expand Up @@ -80,3 +80,18 @@ magicTrick('DIAMONDS'); // Error: 'DIAMONDS' is a key, but not a value.
magicTrick('Magic'); // Error: 'Magic' is not a value.
magicTrick(('Diamonds': string)); // Error: the `string` type is to general and
// not a value.

// same as Suite above, but uses Object.freeze instead of needing an
// annotation.
const FrozenSuite = Object.freeze({
DIAMONDS: 'Diamonds',
CLUBS: 'Clubs',
HEARTS: 'Hearts',
SPADES: 'Spades',
});
type FrozenSuiteEnum = $Values<typeof FrozenSuite>
('Diamonds': FrozenSuiteEnum); // ok
(DIAMONDS: FrozenSuiteEnum); // ok
('DIAMONDS': FrozenSuiteEnum); // Error: 'DIAMONDS' is a key, but not a value.
('Magic': FrozenSuiteEnum); // Error: 'Magic' is not a value.
(('Diamonds': string): FrozenSuiteEnum); // Error: `string` is too general
20 changes: 19 additions & 1 deletion tests/values/values.exp
Expand Up @@ -366,5 +366,23 @@ Error: object_types.js:81
64: function magicTrick(suite: SuiteEnum) {
^^^^^^^^^ string enum

Error: object_types.js:95
95: ('DIAMONDS': FrozenSuiteEnum); // Error: 'DIAMONDS' is a key, but not a value.
^^^^^^^^^^ string. This type is incompatible with
95: ('DIAMONDS': FrozenSuiteEnum); // Error: 'DIAMONDS' is a key, but not a value.
^^^^^^^^^^^^^^^ string enum

Error: object_types.js:96
96: ('Magic': FrozenSuiteEnum); // Error: 'Magic' is not a value.
^^^^^^^ string. This type is incompatible with
96: ('Magic': FrozenSuiteEnum); // Error: 'Magic' is not a value.
^^^^^^^^^^^^^^^ string enum

Error: object_types.js:97
97: (('Diamonds': string): FrozenSuiteEnum); // Error: `string` is too general
^^^^^^ string. This type is incompatible with
97: (('Diamonds': string): FrozenSuiteEnum); // Error: `string` is too general
^^^^^^^^^^^^^^^ string enum


Found 36 errors
Found 39 errors

0 comments on commit 7c3390f

Please sign in to comment.