Sync the Flow tests (#1163)
* Extract custom tests from tests/flow/ Approach: 1. Remove all .js files in tests/flow except .snap.js files. 2. Copy over all .js files from tests/ in the flow repo. 3. Go through the diff looking for deletions. - It was easy to see which deletions were due to changes in the tests due to updates in the flow repo. - For the rest of the deletions, I used `git blame` to verify that they had been added by us since the flow tests were copied over. This makes tests/flow/ simply a copy of the tests from the flow repo, making it easier to sync with the upstream flow tests in the future. * Add a script for syncing the flow tests * Sync the flow testsmaster
parent
bfd5fa4515
commit
dc93bdc983
45
README.md
45
README.md
|
@ -442,23 +442,30 @@ Show the world you're using *Prettier* → [![styled with prettier](https://img.
|
|||
|
||||
## Contributing
|
||||
|
||||
We will work on better docs over time, but in the mean time, here are
|
||||
a few notes if you are interested in contributing:
|
||||
To get up and running, install the dependencies and run the tests:
|
||||
|
||||
* You should be able to get up and running with just `yarn`.
|
||||
* This uses [Jest](https://facebook.github.io/jest/) snapshots for tests. The entire Flow test suite is
|
||||
included here. You can make changes and run `jest -u`, and then
|
||||
`git diff` to see the styles that changed. Always update the
|
||||
snapshots if opening a PR.
|
||||
* If you can, look at [commands.md](commands.md) and check out
|
||||
[Wadler's paper](http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf)
|
||||
to understand how this works. I will try to write a better explanation soon.
|
||||
* I haven't set up any automated tests yet, but for now as long as you
|
||||
run `jest -u` to update the snapshots and I see them in the PR, that's fine.
|
||||
* You can run `AST_COMPARE=1 jest` for a more robust test run. That
|
||||
formats each file, re-parses it, and compares the new AST with the
|
||||
original one and makes sure they are semantically equivalent.
|
||||
* Each test folder has a `jsfmt.spec.js` that runs the tests.
|
||||
Normally you can just put `run_spec(__dirname);` there but if you want to pass
|
||||
specific options, you can add the options object as the 2nd parameter like:
|
||||
`run_spec(__dirname, { parser: 'babylon' });`
|
||||
```
|
||||
yarn
|
||||
yarn test
|
||||
```
|
||||
|
||||
Here's what you need to know about the tests:
|
||||
|
||||
* The tests uses [Jest](https://facebook.github.io/jest/) snapshots.
|
||||
* You can make changes and run `jest -u` to update the snapshots. Then run `git
|
||||
diff` to take a look at what changed. Always update the snapshots when opening
|
||||
a PR.
|
||||
* You can run `AST_COMPARE=1 jest` for a more robust test run. That formats each
|
||||
file, re-parses it, and compares the new AST with the original one and makes
|
||||
sure they are semantically equivalent.
|
||||
* Each test folder has a `jsfmt.spec.js` that runs the tests. Normally you can
|
||||
just put `run_spec(__dirname);` there. You can also pass options and
|
||||
additional parsers, like this:
|
||||
`run_spec(__dirname, { trailingComma: "es5" }, ["babylon"]);`
|
||||
* `tests/flow/` contains the Flow test suite, and is not supposed to be edited
|
||||
by hand. To update it, clone the Flow repo next to the Prettier repo and run:
|
||||
`node scripts/sync-flow-tests.js ../flow/tests/`.
|
||||
|
||||
If you can, take look at [commands.md](commands.md) and check out [Wadler's
|
||||
paper](http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf) to
|
||||
understand how Prettier works.
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
"devDependencies": {
|
||||
"diff": "3.2.0",
|
||||
"jest": "19.0.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"rimraf": "^2.6.1",
|
||||
"rollup": "0.41.1",
|
||||
"rollup-plugin-commonjs": "7.0.0",
|
||||
"rollup-plugin-json": "2.1.0",
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
const fs = require("fs");
|
||||
const flowParser = require("flow-parser");
|
||||
const glob = require("glob");
|
||||
const mkdirp = require("mkdirp");
|
||||
const path = require("path");
|
||||
const rimraf = require("rimraf");
|
||||
|
||||
const DEFAULT_SPEC_CONTENT = "run_spec(__dirname);\n";
|
||||
const SPEC_FILE_NAME = "jsfmt.spec.js";
|
||||
const FLOW_TESTS_DIR = path.join(__dirname, "..", "tests", "flow");
|
||||
|
||||
function tryParse(file, content) {
|
||||
const ast = flowParser.parse(content, {
|
||||
esproposal_class_instance_fields: true,
|
||||
esproposal_class_static_fields: true,
|
||||
esproposal_export_star_as: true
|
||||
});
|
||||
|
||||
if (ast.errors.length > 0) {
|
||||
const line = ast.errors[0].loc.start.line;
|
||||
const column = ast.errors[0].loc.start.column;
|
||||
const message = ast.errors[0].message;
|
||||
return `${file}:${line}:${column}: ${message}`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function syncTests(syncDir) {
|
||||
const specFiles = glob.sync(path.join(FLOW_TESTS_DIR, "**", SPEC_FILE_NAME));
|
||||
const filesToCopy = glob.sync(path.join(syncDir, "**/*.js"));
|
||||
|
||||
if (filesToCopy.length === 0) {
|
||||
throw new Error(
|
||||
[
|
||||
"Couldn't find any files to copy.",
|
||||
`Please make sure that \`${syncDir}\` exists and contains the flow tests.`
|
||||
].join("\n")
|
||||
)
|
||||
}
|
||||
|
||||
const specContents = specFiles.reduce((obj, specFile) => {
|
||||
obj[specFile] = fs.readFileSync(specFile, "utf8");
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
const skipped = [];
|
||||
|
||||
rimraf.sync(FLOW_TESTS_DIR);
|
||||
|
||||
filesToCopy.forEach(file => {
|
||||
const content = fs.readFileSync(file, "utf8");
|
||||
const parseError = tryParse(file, content);
|
||||
|
||||
if (parseError) {
|
||||
skipped.push(parseError);
|
||||
return;
|
||||
}
|
||||
|
||||
const newFile = path.join(FLOW_TESTS_DIR, path.relative(syncDir, file));
|
||||
const dirname = path.dirname(newFile);
|
||||
const specFile = path.join(dirname, SPEC_FILE_NAME);
|
||||
const specContent = specContents[specFile] || DEFAULT_SPEC_CONTENT;
|
||||
|
||||
mkdirp.sync(dirname);
|
||||
fs.writeFileSync(newFile, content);
|
||||
fs.writeFileSync(specFile, specContent);
|
||||
});
|
||||
|
||||
return skipped;
|
||||
}
|
||||
|
||||
function run(argv) {
|
||||
if (argv.length !== 1) {
|
||||
console.error(
|
||||
[
|
||||
"You must provide the path to a flow tests directory to sync from!",
|
||||
"Example: node scripts/sync-flow-tests.js ../flow/tests/"
|
||||
].join("\n")
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const syncDir = argv[0];
|
||||
let skipped = [];
|
||||
|
||||
try {
|
||||
skipped = syncTests(syncDir);
|
||||
} catch (error) {
|
||||
console.error(`Failed to sync.\n${error}`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (skipped.length > 0) {
|
||||
console.log(
|
||||
[
|
||||
"Some files were skipped due to syntax errors.",
|
||||
"This is expected since flow tests for handling invalid code,",
|
||||
"but that's not interesting for Prettier's tests.",
|
||||
"This is the skipped stuff:",
|
||||
""
|
||||
]
|
||||
.concat(skipped, "")
|
||||
.join("\n")
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
[
|
||||
"Done syncing! Now you need to:",
|
||||
"",
|
||||
`1. Optional: Adjust some ${SPEC_FILE_NAME} files.`,
|
||||
"2. Run `jest -u` to create snapshots.",
|
||||
"3. Run `git diff` to check how tests and snapshots have changed",
|
||||
"4. Take a look at new snapshots to see if they're OK."
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
const exitCode = run(process.argv.slice(2));
|
||||
process.exit(exitCode);
|
||||
}
|
|
@ -39,3 +39,14 @@ function foo() {
|
|||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`toplevel_throw.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
throw new Error('foo'); // no error
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
throw new Error(\\"foo\\"); // no error
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
throw new Error('foo'); // no error
|
|
@ -61,38 +61,6 @@ var zer : null = null;
|
|||
|
||||
function foobar(n : ?number) : number | null | void { return n; }
|
||||
function barfoo(n : number | null | void) : ?number { return n; }
|
||||
|
||||
type Banana = {
|
||||
eat: string => boolean,
|
||||
};
|
||||
|
||||
type Hex = {n: 0x01};
|
||||
|
||||
type T = { method: (a) => void };
|
||||
|
||||
type T = { method(a): void };
|
||||
|
||||
declare class X { method(a): void }
|
||||
|
||||
declare function f(a): void;
|
||||
|
||||
var f: (a) => void;
|
||||
|
||||
interface F { m(string): number }
|
||||
|
||||
interface F { m: (string) => number }
|
||||
|
||||
function f(o: { f: (string) => void }) {}
|
||||
|
||||
function f(o: { f(string): void }) {}
|
||||
|
||||
type f = (...arg) => void;
|
||||
|
||||
type f = (/* comment */ arg) => void;
|
||||
|
||||
type f = (arg /* comment */) => void;
|
||||
|
||||
type f = (?arg) => void;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
function foo(str: string, i: number): string {
|
||||
return str;
|
||||
|
@ -163,38 +131,6 @@ function foobar(n: ?number): number | null | void {
|
|||
function barfoo(n: number | null | void): ?number {
|
||||
return n;
|
||||
}
|
||||
|
||||
type Banana = {
|
||||
eat: string => boolean
|
||||
};
|
||||
|
||||
type Hex = { n: 0x01 };
|
||||
|
||||
type T = { method: a => void };
|
||||
|
||||
type T = { method(a): void };
|
||||
|
||||
declare class X { method(a): void }
|
||||
|
||||
declare function f(a): void;
|
||||
|
||||
var f: a => void;
|
||||
|
||||
interface F { m(string): number }
|
||||
|
||||
interface F { m: string => number }
|
||||
|
||||
function f(o: { f: string => void }) {}
|
||||
|
||||
function f(o: { f(string): void }) {}
|
||||
|
||||
type f = (...arg) => void;
|
||||
|
||||
type f = /* comment */ arg => void;
|
||||
|
||||
type f = arg /* comment */ => void;
|
||||
|
||||
type f = ?arg => void;
|
||||
"
|
||||
`;
|
||||
|
||||
|
|
|
@ -58,35 +58,3 @@ var zer : null = null;
|
|||
|
||||
function foobar(n : ?number) : number | null | void { return n; }
|
||||
function barfoo(n : number | null | void) : ?number { return n; }
|
||||
|
||||
type Banana = {
|
||||
eat: string => boolean,
|
||||
};
|
||||
|
||||
type Hex = {n: 0x01};
|
||||
|
||||
type T = { method: (a) => void };
|
||||
|
||||
type T = { method(a): void };
|
||||
|
||||
declare class X { method(a): void }
|
||||
|
||||
declare function f(a): void;
|
||||
|
||||
var f: (a) => void;
|
||||
|
||||
interface F { m(string): number }
|
||||
|
||||
interface F { m: (string) => number }
|
||||
|
||||
function f(o: { f: (string) => void }) {}
|
||||
|
||||
function f(o: { f(string): void }) {}
|
||||
|
||||
type f = (...arg) => void;
|
||||
|
||||
type f = (/* comment */ arg) => void;
|
||||
|
||||
type f = (arg /* comment */) => void;
|
||||
|
||||
type f = (?arg) => void;
|
||||
|
|
|
@ -82,27 +82,6 @@ module.exports = \\"arrays\\";
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`comments.js 1`] = `
|
||||
"export type FileMetaData = [
|
||||
/* id */ string,
|
||||
/* mtime */ number,
|
||||
/* visited */ 0|1,
|
||||
/* dependencies */ Array<string>,
|
||||
];
|
||||
|
||||
export type ModuleMetaData = [Path, /* type */ number];
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
export type FileMetaData = [
|
||||
/* id */ string,
|
||||
/* mtime */ number,
|
||||
/* visited */ 0 | 1,
|
||||
/* dependencies */ Array<string>
|
||||
];
|
||||
|
||||
export type ModuleMetaData = [Path, /* type */ number];
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`numeric_elem.js 1`] = `
|
||||
"var arr = [];
|
||||
var day = new Date;
|
||||
|
@ -121,10 +100,3 @@ arr[day] = 0;
|
|||
(arr[day]: string); // error: number ~> string
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`union.js 1`] = `
|
||||
"let arr: (number|string)[] = [];
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
let arr: (number | string)[] = [];
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
const Immutable = require('immutable');
|
||||
|
||||
const tasksPerStatusMap = new Map(
|
||||
[].map(taskStatus => [taskStatus, new Map()]),
|
||||
);
|
||||
for (let [taskStatus, tasksMap] of tasksPerStatusMap) {
|
||||
tasksPerStatusMap.set(taskStatus, Immutable.Map(tasksMap));
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
const Immutable = require(\\"immutable\\");
|
||||
|
||||
const tasksPerStatusMap = new Map(
|
||||
[].map(taskStatus => [taskStatus, new Map()])
|
||||
);
|
||||
for (let [taskStatus, tasksMap] of tasksPerStatusMap) {
|
||||
tasksPerStatusMap.set(taskStatus, Immutable.Map(tasksMap));
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`test2.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
declare class Bar<K> {
|
||||
update<K_>(updater: (value: this) => Bar<K_>): Bar<K_>;
|
||||
}
|
||||
|
||||
declare function foo<U>(
|
||||
initialValue: U,
|
||||
callbackfn: (previousValue: U) => U
|
||||
): U;
|
||||
|
||||
declare var items: Bar<string>;
|
||||
declare var updater: (value: Bar<string>) => Bar<string>;
|
||||
|
||||
foo(
|
||||
items,
|
||||
(acc) => acc.update(updater)
|
||||
);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
declare class Bar<K> {
|
||||
update<K_>(updater: (value: this) => Bar<K_>): Bar<K_>
|
||||
}
|
||||
|
||||
declare function foo<U>(
|
||||
initialValue: U,
|
||||
callbackfn: (previousValue: U) => U
|
||||
): U;
|
||||
|
||||
declare var items: Bar<string>;
|
||||
declare var updater: (value: Bar<string>) => Bar<string>;
|
||||
|
||||
foo(items, acc => acc.update(updater));
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`test3.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
declare class ImmBox<T> {
|
||||
static <U>(x: any): ImmBox<U>;
|
||||
static (x: any): any;
|
||||
}
|
||||
|
||||
declare class Box<T> {
|
||||
constructor(x: T): void;
|
||||
set(value: T): void;
|
||||
get(): T;
|
||||
}
|
||||
|
||||
const outer = new Box();
|
||||
const inner = outer.get();
|
||||
outer.set(ImmBox(inner));
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
declare class ImmBox<T> {
|
||||
static <U>(x: any): ImmBox<U>,
|
||||
static (x: any): any
|
||||
}
|
||||
|
||||
declare class Box<T> {
|
||||
constructor(x: T): void,
|
||||
set(value: T): void,
|
||||
get(): T
|
||||
}
|
||||
|
||||
const outer = new Box();
|
||||
const inner = outer.get();
|
||||
outer.set(ImmBox(inner));
|
||||
"
|
||||
`;
|
|
@ -0,0 +1,80 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`core.js 1`] = `
|
||||
"declare class Array<T> {
|
||||
@@iterator(): Iterator<T>;
|
||||
map<U>(callbackfn: (value: T, index: number, array: Array<T>) => U, thisArg?: any): Array<U>;
|
||||
}
|
||||
|
||||
type IteratorResult<Yield,Return> =
|
||||
| { done: true, value?: Return }
|
||||
| { done: false, value: Yield };
|
||||
|
||||
interface $Iterator<+Yield,+Return,-Next> {
|
||||
@@iterator(): $Iterator<Yield,Return,Next>;
|
||||
next(value?: Next): IteratorResult<Yield,Return>;
|
||||
}
|
||||
type Iterator<+T> = $Iterator<T,void,void>;
|
||||
|
||||
interface $Iterable<+Yield,+Return,-Next> {
|
||||
@@iterator(): $Iterator<Yield,Return,Next>;
|
||||
}
|
||||
type Iterable<+T> = $Iterable<T,void,void>;
|
||||
|
||||
declare class Map<K, V> {
|
||||
@@iterator(): Iterator<[K, V]>;
|
||||
constructor(iterable: ?Iterable<[K, V]>): void;
|
||||
set(key: K, value: V): Map<K, V>;
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
declare class Array<T> {
|
||||
@@iterator(): Iterator<T>,
|
||||
map<U>(
|
||||
callbackfn: (value: T, index: number, array: Array<T>) => U,
|
||||
thisArg?: any
|
||||
): Array<U>
|
||||
}
|
||||
|
||||
type IteratorResult<Yield, Return> =
|
||||
| { done: true, value?: Return }
|
||||
| { done: false, value: Yield };
|
||||
|
||||
interface $Iterator<+Yield, +Return, -Next> {
|
||||
@@iterator(): $Iterator<Yield, Return, Next>,
|
||||
next(value?: Next): IteratorResult<Yield, Return>
|
||||
}
|
||||
type Iterator<+T> = $Iterator<T, void, void>;
|
||||
|
||||
interface $Iterable<+Yield, +Return, -Next> {
|
||||
@@iterator(): $Iterator<Yield, Return, Next>
|
||||
}
|
||||
type Iterable<+T> = $Iterable<T, void, void>;
|
||||
|
||||
declare class Map<K, V> {
|
||||
@@iterator(): Iterator<[K, V]>,
|
||||
constructor(iterable: ?Iterable<[K, V]>): void,
|
||||
set(key: K, value: V): Map<K, V>
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`immutable.js 1`] = `
|
||||
"declare module \\"immutable\\" {
|
||||
declare class Map<K,V> {
|
||||
static <K,V>(iter: Iterator<[K,V]>): Map<K,V>;
|
||||
static <K:string,V>(object: {+[k:K]:V}): Map<K,V>;
|
||||
|
||||
set(key: K, value: V): this;
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
declare module \\"immutable\\" {
|
||||
declare class Map<K, V> {
|
||||
static <K, V>(iter: Iterator<[K, V]>): Map<K, V>,
|
||||
static <K: string, V>(object: { +[k: K]: V }): Map<K, V>,
|
||||
|
||||
set(key: K, value: V): this
|
||||
}
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1,25 @@
|
|||
declare class Array<T> {
|
||||
@@iterator(): Iterator<T>;
|
||||
map<U>(callbackfn: (value: T, index: number, array: Array<T>) => U, thisArg?: any): Array<U>;
|
||||
}
|
||||
|
||||
type IteratorResult<Yield,Return> =
|
||||
| { done: true, value?: Return }
|
||||
| { done: false, value: Yield };
|
||||
|
||||
interface $Iterator<+Yield,+Return,-Next> {
|
||||
@@iterator(): $Iterator<Yield,Return,Next>;
|
||||
next(value?: Next): IteratorResult<Yield,Return>;
|
||||
}
|
||||
type Iterator<+T> = $Iterator<T,void,void>;
|
||||
|
||||
interface $Iterable<+Yield,+Return,-Next> {
|
||||
@@iterator(): $Iterator<Yield,Return,Next>;
|
||||
}
|
||||
type Iterable<+T> = $Iterable<T,void,void>;
|
||||
|
||||
declare class Map<K, V> {
|
||||
@@iterator(): Iterator<[K, V]>;
|
||||
constructor(iterable: ?Iterable<[K, V]>): void;
|
||||
set(key: K, value: V): Map<K, V>;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
declare module "immutable" {
|
||||
declare class Map<K,V> {
|
||||
static <K,V>(iter: Iterator<[K,V]>): Map<K,V>;
|
||||
static <K:string,V>(object: {+[k:K]:V}): Map<K,V>;
|
||||
|
||||
set(key: K, value: V): this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,10 @@
|
|||
// @flow
|
||||
|
||||
const Immutable = require('immutable');
|
||||
|
||||
const tasksPerStatusMap = new Map(
|
||||
[].map(taskStatus => [taskStatus, new Map()]),
|
||||
);
|
||||
for (let [taskStatus, tasksMap] of tasksPerStatusMap) {
|
||||
tasksPerStatusMap.set(taskStatus, Immutable.Map(tasksMap));
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* @flow */
|
||||
|
||||
declare class Bar<K> {
|
||||
update<K_>(updater: (value: this) => Bar<K_>): Bar<K_>;
|
||||
}
|
||||
|
||||
declare function foo<U>(
|
||||
initialValue: U,
|
||||
callbackfn: (previousValue: U) => U
|
||||
): U;
|
||||
|
||||
declare var items: Bar<string>;
|
||||
declare var updater: (value: Bar<string>) => Bar<string>;
|
||||
|
||||
foo(
|
||||
items,
|
||||
(acc) => acc.update(updater)
|
||||
);
|
|
@ -0,0 +1,16 @@
|
|||
// @flow
|
||||
|
||||
declare class ImmBox<T> {
|
||||
static <U>(x: any): ImmBox<U>;
|
||||
static (x: any): any;
|
||||
}
|
||||
|
||||
declare class Box<T> {
|
||||
constructor(x: T): void;
|
||||
set(value: T): void;
|
||||
get(): T;
|
||||
}
|
||||
|
||||
const outer = new Box();
|
||||
const inner = outer.get();
|
||||
outer.set(ImmBox(inner));
|
|
@ -0,0 +1,16 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
function Foo(items: ?Iterable<number>) {
|
||||
Iterable(items || []).size;
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
function Foo(items: ?Iterable<number>) {
|
||||
Iterable(items || []).size;
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,24 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`immutable.js 1`] = `
|
||||
"// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
declare class Array<T> { }
|
||||
|
||||
declare class Iterable<S> {
|
||||
static <V,Iter:Iterable<V>>(iter: Iter): Iter;
|
||||
static <T>(iter: Array<T>): Iterable<T>;
|
||||
size: number;
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
declare class Array<T> {}
|
||||
|
||||
declare class Iterable<S> {
|
||||
static <V, Iter: Iterable<V>>(iter: Iter): Iter,
|
||||
static <T>(iter: Array<T>): Iterable<T>,
|
||||
size: number
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
declare class Array<T> { }
|
||||
|
||||
declare class Iterable<S> {
|
||||
static <V,Iter:Iterable<V>>(iter: Iter): Iter;
|
||||
static <T>(iter: Array<T>): Iterable<T>;
|
||||
size: number;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,5 @@
|
|||
// @flow
|
||||
|
||||
function Foo(items: ?Iterable<number>) {
|
||||
Iterable(items || []).size;
|
||||
}
|
|
@ -0,0 +1,573 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`base_class.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
class Base {
|
||||
unannotatedField;
|
||||
annotatedField: number;
|
||||
initializedField = 42;
|
||||
initializedFieldWithThis = this.initializedField;
|
||||
annotatedInitializedFieldValid: ?number = 42;
|
||||
annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
static unannotatedField;
|
||||
static annotatedField: number;
|
||||
static initializedField = 'asdf';
|
||||
static initializedFieldWithThis = this.initializedField;
|
||||
static annotatedInitializedFieldValid: ?number = 42;
|
||||
static annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
}
|
||||
|
||||
var o = new Base();
|
||||
|
||||
/**
|
||||
* Unannotated fields are open.
|
||||
*/
|
||||
(o.unannotatedField: string);
|
||||
(o.unannotatedField: number);
|
||||
(Base.unannotatedField: string);
|
||||
(Base.unannotatedField: number);
|
||||
|
||||
/**
|
||||
* Annotated (but uninitialized) fields still have a type.
|
||||
*/
|
||||
(o.annotatedField: number);
|
||||
(o.annotatedField: string); // Error: number ~> string
|
||||
(Base.annotatedField: number);
|
||||
(Base.annotatedField: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Initialized (but unannotated) fields assume the type of their initializer.
|
||||
*/
|
||||
(o.initializedField: number);
|
||||
(o.initializedField: string); // Error: number ~> string
|
||||
(Base.initializedField: string);
|
||||
(Base.initializedField: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized fields can reference \`this\`.
|
||||
*/
|
||||
(o.initializedFieldWithThis: number);
|
||||
(o.initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Base.initializedFieldWithThis: string);
|
||||
(Base.initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields take the type of the annotation.
|
||||
* (Note that this matters when the annotation is more general than the type of
|
||||
* the initializer)
|
||||
*/
|
||||
(o.annotatedInitializedFieldValid: ?number);
|
||||
(o.annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Base.annotatedInitializedFieldValid: ?number);
|
||||
(Base.annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields where the init/annot combo is a mismatch
|
||||
* should assume the type of the annotation.
|
||||
*
|
||||
* (This happens in addition to erroring at the site of initialization)
|
||||
*/
|
||||
(o.annotatedInitializedFieldInvalid: number);
|
||||
(o.annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Base.annotatedInitializedFieldInvalid: number);
|
||||
(Base.annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
class Base {
|
||||
unannotatedField;
|
||||
annotatedField: number;
|
||||
initializedField = 42;
|
||||
initializedFieldWithThis = this.initializedField;
|
||||
annotatedInitializedFieldValid: ?number = 42;
|
||||
annotatedInitializedFieldInvalid: number = \\"asdf\\"; // Error: string ~> number
|
||||
|
||||
static unannotatedField;
|
||||
static annotatedField: number;
|
||||
static initializedField = \\"asdf\\";
|
||||
static initializedFieldWithThis = this.initializedField;
|
||||
static annotatedInitializedFieldValid: ?number = 42;
|
||||
static annotatedInitializedFieldInvalid: number = \\"asdf\\"; // Error: string ~> number
|
||||
}
|
||||
|
||||
var o = new Base();
|
||||
|
||||
/**
|
||||
* Unannotated fields are open.
|
||||
*/
|
||||
(o.unannotatedField: string);
|
||||
(o.unannotatedField: number);
|
||||
(Base.unannotatedField: string);
|
||||
(Base.unannotatedField: number);
|
||||
|
||||
/**
|
||||
* Annotated (but uninitialized) fields still have a type.
|
||||
*/
|
||||
(o.annotatedField: number);
|
||||
(o.annotatedField: string); // Error: number ~> string
|
||||
(Base.annotatedField: number);
|
||||
(Base.annotatedField: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Initialized (but unannotated) fields assume the type of their initializer.
|
||||
*/
|
||||
(o.initializedField: number);
|
||||
(o.initializedField: string); // Error: number ~> string
|
||||
(Base.initializedField: string);
|
||||
(Base.initializedField: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized fields can reference \`this\`.
|
||||
*/
|
||||
(o.initializedFieldWithThis: number);
|
||||
(o.initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Base.initializedFieldWithThis: string);
|
||||
(Base.initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields take the type of the annotation.
|
||||
* (Note that this matters when the annotation is more general than the type of
|
||||
* the initializer)
|
||||
*/
|
||||
(o.annotatedInitializedFieldValid: ?number);
|
||||
(o.annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Base.annotatedInitializedFieldValid: ?number);
|
||||
(Base.annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields where the init/annot combo is a mismatch
|
||||
* should assume the type of the annotation.
|
||||
*
|
||||
* (This happens in addition to erroring at the site of initialization)
|
||||
*/
|
||||
(o.annotatedInitializedFieldInvalid: number);
|
||||
(o.annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Base.annotatedInitializedFieldInvalid: number);
|
||||
(Base.annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`derived_class.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
class Base {
|
||||
base_unannotatedField;
|
||||
base_annotatedField: number;
|
||||
base_initializedField = 42;
|
||||
base_initializedFieldWithThis = this.base_initializedField;
|
||||
base_annotatedInitializedFieldValid: ?number = 42;
|
||||
base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
static base_unannotatedField;
|
||||
static base_annotatedField: number;
|
||||
static base_initializedField = 'asdf';
|
||||
static base_initializedFieldWithThis = this.base_initializedField;
|
||||
static base_annotatedInitializedFieldValid: ?number = 42;
|
||||
static base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
inherited_initializer = 42;
|
||||
static inherited_initializer = 42;
|
||||
}
|
||||
|
||||
class Child extends Base {
|
||||
child_unannotatedField;
|
||||
child_annotatedField: number;
|
||||
child_initializedField = 42;
|
||||
child_initializedFieldWithThis = this.child_initializedField;
|
||||
child_annotatedInitializedFieldValid: ?number = 42;
|
||||
child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
static child_unannotatedField;
|
||||
static child_annotatedField: number;
|
||||
static child_initializedField = 'asdf';
|
||||
static child_initializedFieldWithThis = this.child_initializedField;
|
||||
static child_annotatedInitializedFieldValid: ?number = 42;
|
||||
static child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
inherited_initializer;
|
||||
static inherited_initializer;
|
||||
}
|
||||
|
||||
var o = new Child();
|
||||
|
||||
/**
|
||||
* Unannotated fields are open.
|
||||
*/
|
||||
(o.base_unannotatedField: string);
|
||||
(o.base_unannotatedField: number);
|
||||
(Child.base_unannotatedField: string);
|
||||
(Child.base_unannotatedField: number);
|
||||
|
||||
(o.child_unannotatedField: string);
|
||||
(o.child_unannotatedField: number);
|
||||
(Child.child_unannotatedField: string);
|
||||
(Child.child_unannotatedField: number);
|
||||
|
||||
|
||||
/**
|
||||
* Annotated (but uninitialized) fields still have a type.
|
||||
*/
|
||||
(o.base_annotatedField: number);
|
||||
(o.base_annotatedField: string); // Error: number ~> string
|
||||
(Child.base_annotatedField: number);
|
||||
(Child.base_annotatedField: string); // Error: number ~> string
|
||||
|
||||
(o.child_annotatedField: number);
|
||||
(o.child_annotatedField: string); // Error: number ~> string
|
||||
(Child.child_annotatedField: number);
|
||||
(Child.child_annotatedField: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Initialized (but unannotated) fields assume the type of their initializer.
|
||||
*/
|
||||
(o.base_initializedField: number);
|
||||
(o.base_initializedField: string); // Error: number ~> string
|
||||
(Child.base_initializedField: string);
|
||||
(Child.base_initializedField: number); // Error: string ~> number
|
||||
|
||||
(o.child_initializedField: number);
|
||||
(o.child_initializedField: string); // Error: number ~> string
|
||||
(Child.child_initializedField: string);
|
||||
(Child.child_initializedField: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized fields can reference \`this\`.
|
||||
*/
|
||||
(o.base_initializedFieldWithThis: number);
|
||||
(o.base_initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Child.base_initializedFieldWithThis: string);
|
||||
(Child.base_initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
(o.child_initializedFieldWithThis: number);
|
||||
(o.child_initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Child.child_initializedFieldWithThis: string);
|
||||
(Child.child_initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields take the type of the annotation.
|
||||
* (Note that this matters when the annotation is more general than the type of
|
||||
* the initializer)
|
||||
*/
|
||||
(o.base_annotatedInitializedFieldValid: ?number);
|
||||
(o.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Child.base_annotatedInitializedFieldValid: ?number);
|
||||
(Child.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
(o.child_annotatedInitializedFieldValid: ?number);
|
||||
(o.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Child.child_annotatedInitializedFieldValid: ?number);
|
||||
(Child.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields where the init/annot combo is a mismatch
|
||||
* should assume the type of the annotation.
|
||||
*
|
||||
* (This happens in addition to erroring at the site of initialization)
|
||||
*/
|
||||
(o.base_annotatedInitializedFieldInvalid: number);
|
||||
(o.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Child.base_annotatedInitializedFieldInvalid: number);
|
||||
(Child.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
|
||||
(o.child_annotatedInitializedFieldInvalid: number);
|
||||
(o.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Child.child_annotatedInitializedFieldInvalid: number);
|
||||
(Child.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Derived fields without an initializer that shadow base fields *with* an
|
||||
* initializer should have the type of the base field.
|
||||
*/
|
||||
(o.inherited_initializer: number);
|
||||
(o.inherited_initializer: string); // Error: number ~> string
|
||||
(Child.inherited_initializer: number);
|
||||
(Child.inherited_initializer: string); // Error: number ~> string
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
class Base {
|
||||
base_unannotatedField;
|
||||
base_annotatedField: number;
|
||||
base_initializedField = 42;
|
||||
base_initializedFieldWithThis = this.base_initializedField;
|
||||
base_annotatedInitializedFieldValid: ?number = 42;
|
||||
base_annotatedInitializedFieldInvalid: number = \\"asdf\\"; // Error: string ~> number
|
||||
|
||||
static base_unannotatedField;
|
||||
static base_annotatedField: number;
|
||||
static base_initializedField = \\"asdf\\";
|
||||
static base_initializedFieldWithThis = this.base_initializedField;
|
||||
static base_annotatedInitializedFieldValid: ?number = 42;
|
||||
static base_annotatedInitializedFieldInvalid: number = \\"asdf\\"; // Error: string ~> number
|
||||
|
||||
inherited_initializer = 42;
|
||||
static inherited_initializer = 42;
|
||||
}
|
||||
|
||||
class Child extends Base {
|
||||
child_unannotatedField;
|
||||
child_annotatedField: number;
|
||||
child_initializedField = 42;
|
||||
child_initializedFieldWithThis = this.child_initializedField;
|
||||
child_annotatedInitializedFieldValid: ?number = 42;
|
||||
child_annotatedInitializedFieldInvalid: number = \\"asdf\\"; // Error: string ~> number
|
||||
|
||||
static child_unannotatedField;
|
||||
static child_annotatedField: number;
|
||||
static child_initializedField = \\"asdf\\";
|
||||
static child_initializedFieldWithThis = this.child_initializedField;
|
||||
static child_annotatedInitializedFieldValid: ?number = 42;
|
||||
static child_annotatedInitializedFieldInvalid: number = \\"asdf\\"; // Error: string ~> number
|
||||
|
||||
inherited_initializer;
|
||||
static inherited_initializer;
|
||||
}
|
||||
|
||||
var o = new Child();
|
||||
|
||||
/**
|
||||
* Unannotated fields are open.
|
||||
*/
|
||||
(o.base_unannotatedField: string);
|
||||
(o.base_unannotatedField: number);
|
||||
(Child.base_unannotatedField: string);
|
||||
(Child.base_unannotatedField: number);
|
||||
|
||||
(o.child_unannotatedField: string);
|
||||
(o.child_unannotatedField: number);
|
||||
(Child.child_unannotatedField: string);
|
||||
(Child.child_unannotatedField: number);
|
||||
|
||||
/**
|
||||
* Annotated (but uninitialized) fields still have a type.
|
||||
*/
|
||||
(o.base_annotatedField: number);
|
||||
(o.base_annotatedField: string); // Error: number ~> string
|
||||
(Child.base_annotatedField: number);
|
||||
(Child.base_annotatedField: string); // Error: number ~> string
|
||||
|
||||
(o.child_annotatedField: number);
|
||||
(o.child_annotatedField: string); // Error: number ~> string
|
||||
(Child.child_annotatedField: number);
|
||||
(Child.child_annotatedField: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Initialized (but unannotated) fields assume the type of their initializer.
|
||||
*/
|
||||
(o.base_initializedField: number);
|
||||
(o.base_initializedField: string); // Error: number ~> string
|
||||
(Child.base_initializedField: string);
|
||||
(Child.base_initializedField: number); // Error: string ~> number
|
||||
|
||||
(o.child_initializedField: number);
|
||||
(o.child_initializedField: string); // Error: number ~> string
|
||||
(Child.child_initializedField: string);
|
||||
(Child.child_initializedField: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized fields can reference \`this\`.
|
||||
*/
|
||||
(o.base_initializedFieldWithThis: number);
|
||||
(o.base_initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Child.base_initializedFieldWithThis: string);
|
||||
(Child.base_initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
(o.child_initializedFieldWithThis: number);
|
||||
(o.child_initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Child.child_initializedFieldWithThis: string);
|
||||
(Child.child_initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields take the type of the annotation.
|
||||
* (Note that this matters when the annotation is more general than the type of
|
||||
* the initializer)
|
||||
*/
|
||||
(o.base_annotatedInitializedFieldValid: ?number);
|
||||
(o.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Child.base_annotatedInitializedFieldValid: ?number);
|
||||
(Child.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
(o.child_annotatedInitializedFieldValid: ?number);
|
||||
(o.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Child.child_annotatedInitializedFieldValid: ?number);
|
||||
(Child.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields where the init/annot combo is a mismatch
|
||||
* should assume the type of the annotation.
|
||||
*
|
||||
* (This happens in addition to erroring at the site of initialization)
|
||||
*/
|
||||
(o.base_annotatedInitializedFieldInvalid: number);
|
||||
(o.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Child.base_annotatedInitializedFieldInvalid: number);
|
||||
(Child.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
|
||||
(o.child_annotatedInitializedFieldInvalid: number);
|
||||
(o.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Child.child_annotatedInitializedFieldInvalid: number);
|
||||
(Child.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Derived fields without an initializer that shadow base fields *with* an
|
||||
* initializer should have the type of the base field.
|
||||
*/
|
||||
(o.inherited_initializer: number);
|
||||
(o.inherited_initializer: string); // Error: number ~> string
|
||||
(Child.inherited_initializer: number);
|
||||
(Child.inherited_initializer: string); // Error: number ~> string
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`generic_class.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
/**
|
||||
* Fields annotated with a generic should assume a type once the type param
|
||||
* is instantiated.
|
||||
*/
|
||||
class ClassAnnotated<T> {
|
||||
p: T;
|
||||
static p: T;
|
||||
}
|
||||
|
||||
var o1 = new ClassAnnotated();
|
||||
o1.p = 42;
|
||||
(o1.p: number);
|
||||
(o1.p: string); // Error: number ~> string
|
||||
ClassAnnotated.p = 42;
|
||||
(ClassAnnotated.p: number);
|
||||
(ClassAnnotated.p: string); // Error: number ~> string
|
||||
|
||||
|
||||
/**
|
||||
* It's always an error to initialized a generically-typed field with an
|
||||
* expression of any type other than the generic itself.
|
||||
*/
|
||||
class ClassGenericInitialized<T, U> {
|
||||
invalid: T = 42; // Error: number ~> Generic<T>
|
||||
valid: T = ((42:any):T);
|
||||
|
||||
static invalid: T = 42; // Error: number ~> Generic<T>
|
||||
static valid: T = ((42:any):T);
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
/**
|
||||
* Fields annotated with a generic should assume a type once the type param
|
||||
* is instantiated.
|
||||
*/
|
||||
class ClassAnnotated<T> {
|
||||
p: T;
|
||||
static p: T;
|
||||
}
|
||||
|
||||
var o1 = new ClassAnnotated();
|
||||
o1.p = 42;
|
||||
(o1.p: number);
|
||||
(o1.p: string); // Error: number ~> string
|
||||
ClassAnnotated.p = 42;
|
||||
(ClassAnnotated.p: number);
|
||||
(ClassAnnotated.p: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* It's always an error to initialized a generically-typed field with an
|
||||
* expression of any type other than the generic itself.
|
||||
*/
|
||||
class ClassGenericInitialized<T, U> {
|
||||
invalid: T = 42; // Error: number ~> Generic<T>
|
||||
valid: T = ((42: any): T);
|
||||
|
||||
static invalid: T = 42; // Error: number ~> Generic<T>
|
||||
static valid: T = ((42: any): T);
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`scoping.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
var someVar = 42;
|
||||
|
||||
class Foo {
|
||||
outer = someVar;
|
||||
selfTyped: Foo;
|
||||
selfTypedInit = new Foo();
|
||||
|
||||
static outer = someVar;
|
||||
static selfTyped: Foo;
|
||||
static selfTypedInit = new Foo();
|
||||
|
||||
constructor() {
|
||||
var someVar = 'asdf';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Field initializers execute in a scope immediately under the scope outside the
|
||||
* class definition.
|
||||
*/
|
||||
(new Foo().outer: number);
|
||||
(new Foo().outer: string); // Error: number ~> string
|
||||
(Foo.outer: number);
|
||||
(Foo.outer: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Field initializers should be able to refer to the class type in their type
|
||||
* annotations.
|
||||
*/
|
||||
(new Foo().selfTyped: Foo);
|
||||
(new Foo().selfTyped: number); // Error: Foo ~> number
|
||||
(Foo.selfTyped: Foo);
|
||||
(Foo.selfTyped: number); // Error: Foo ~> number
|
||||
|
||||
(new Foo().selfTypedInit: Foo);
|
||||
(new Foo().selfTypedInit: number); // Error: Foo ~> number
|
||||
(Foo.selfTypedInit: Foo);
|
||||
(Foo.selfTypedInit: number); // Error: Foo ~> number
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
var someVar = 42;
|
||||
|
||||
class Foo {
|
||||
outer = someVar;
|
||||
selfTyped: Foo;
|
||||
selfTypedInit = new Foo();
|
||||
|
||||
static outer = someVar;
|
||||
static selfTyped: Foo;
|
||||
static selfTypedInit = new Foo();
|
||||
|
||||
constructor() {
|
||||
var someVar = \\"asdf\\";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Field initializers execute in a scope immediately under the scope outside the
|
||||
* class definition.
|
||||
*/
|
||||
(new Foo().outer: number);
|
||||
(new Foo().outer: string); // Error: number ~> string
|
||||
(Foo.outer: number);
|
||||
(Foo.outer: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Field initializers should be able to refer to the class type in their type
|
||||
* annotations.
|
||||
*/
|
||||
(new Foo().selfTyped: Foo);
|
||||
(new Foo().selfTyped: number); // Error: Foo ~> number
|
||||
(Foo.selfTyped: Foo);
|
||||
(Foo.selfTyped: number); // Error: Foo ~> number
|
||||
|
||||
(new Foo().selfTypedInit: Foo);
|
||||
(new Foo().selfTypedInit: number); // Error: Foo ~> number
|
||||
(Foo.selfTypedInit: Foo);
|
||||
(Foo.selfTypedInit: number); // Error: Foo ~> number
|
||||
"
|
||||
`;
|
|
@ -0,0 +1,72 @@
|
|||
// @flow
|
||||
|
||||
class Base {
|
||||
unannotatedField;
|
||||
annotatedField: number;
|
||||
initializedField = 42;
|
||||
initializedFieldWithThis = this.initializedField;
|
||||
annotatedInitializedFieldValid: ?number = 42;
|
||||
annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
static unannotatedField;
|
||||
static annotatedField: number;
|
||||
static initializedField = 'asdf';
|
||||
static initializedFieldWithThis = this.initializedField;
|
||||
static annotatedInitializedFieldValid: ?number = 42;
|
||||
static annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
}
|
||||
|
||||
var o = new Base();
|
||||
|
||||
/**
|
||||
* Unannotated fields are open.
|
||||
*/
|
||||
(o.unannotatedField: string);
|
||||
(o.unannotatedField: number);
|
||||
(Base.unannotatedField: string);
|
||||
(Base.unannotatedField: number);
|
||||
|
||||
/**
|
||||
* Annotated (but uninitialized) fields still have a type.
|
||||
*/
|
||||
(o.annotatedField: number);
|
||||
(o.annotatedField: string); // Error: number ~> string
|
||||
(Base.annotatedField: number);
|
||||
(Base.annotatedField: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Initialized (but unannotated) fields assume the type of their initializer.
|
||||
*/
|
||||
(o.initializedField: number);
|
||||
(o.initializedField: string); // Error: number ~> string
|
||||
(Base.initializedField: string);
|
||||
(Base.initializedField: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized fields can reference `this`.
|
||||
*/
|
||||
(o.initializedFieldWithThis: number);
|
||||
(o.initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Base.initializedFieldWithThis: string);
|
||||
(Base.initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields take the type of the annotation.
|
||||
* (Note that this matters when the annotation is more general than the type of
|
||||
* the initializer)
|
||||
*/
|
||||
(o.annotatedInitializedFieldValid: ?number);
|
||||
(o.annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Base.annotatedInitializedFieldValid: ?number);
|
||||
(Base.annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields where the init/annot combo is a mismatch
|
||||
* should assume the type of the annotation.
|
||||
*
|
||||
* (This happens in addition to erroring at the site of initialization)
|
||||
*/
|
||||
(o.annotatedInitializedFieldInvalid: number);
|
||||
(o.annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Base.annotatedInitializedFieldInvalid: number);
|
||||
(Base.annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
|
@ -0,0 +1,134 @@
|
|||
// @flow
|
||||
|
||||
class Base {
|
||||
base_unannotatedField;
|
||||
base_annotatedField: number;
|
||||
base_initializedField = 42;
|
||||
base_initializedFieldWithThis = this.base_initializedField;
|
||||
base_annotatedInitializedFieldValid: ?number = 42;
|
||||
base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
static base_unannotatedField;
|
||||
static base_annotatedField: number;
|
||||
static base_initializedField = 'asdf';
|
||||
static base_initializedFieldWithThis = this.base_initializedField;
|
||||
static base_annotatedInitializedFieldValid: ?number = 42;
|
||||
static base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
inherited_initializer = 42;
|
||||
static inherited_initializer = 42;
|
||||
}
|
||||
|
||||
class Child extends Base {
|
||||
child_unannotatedField;
|
||||
child_annotatedField: number;
|
||||
child_initializedField = 42;
|
||||
child_initializedFieldWithThis = this.child_initializedField;
|
||||
child_annotatedInitializedFieldValid: ?number = 42;
|
||||
child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
static child_unannotatedField;
|
||||
static child_annotatedField: number;
|
||||
static child_initializedField = 'asdf';
|
||||
static child_initializedFieldWithThis = this.child_initializedField;
|
||||
static child_annotatedInitializedFieldValid: ?number = 42;
|
||||
static child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
|
||||
|
||||
inherited_initializer;
|
||||
static inherited_initializer;
|
||||
}
|
||||
|
||||
var o = new Child();
|
||||
|
||||
/**
|
||||
* Unannotated fields are open.
|
||||
*/
|
||||
(o.base_unannotatedField: string);
|
||||
(o.base_unannotatedField: number);
|
||||
(Child.base_unannotatedField: string);
|
||||
(Child.base_unannotatedField: number);
|
||||
|
||||
(o.child_unannotatedField: string);
|
||||
(o.child_unannotatedField: number);
|
||||
(Child.child_unannotatedField: string);
|
||||
(Child.child_unannotatedField: number);
|
||||
|
||||
|
||||
/**
|
||||
* Annotated (but uninitialized) fields still have a type.
|
||||
*/
|
||||
(o.base_annotatedField: number);
|
||||
(o.base_annotatedField: string); // Error: number ~> string
|
||||
(Child.base_annotatedField: number);
|
||||
(Child.base_annotatedField: string); // Error: number ~> string
|
||||
|
||||
(o.child_annotatedField: number);
|
||||
(o.child_annotatedField: string); // Error: number ~> string
|
||||
(Child.child_annotatedField: number);
|
||||
(Child.child_annotatedField: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Initialized (but unannotated) fields assume the type of their initializer.
|
||||
*/
|
||||
(o.base_initializedField: number);
|
||||
(o.base_initializedField: string); // Error: number ~> string
|
||||
(Child.base_initializedField: string);
|
||||
(Child.base_initializedField: number); // Error: string ~> number
|
||||
|
||||
(o.child_initializedField: number);
|
||||
(o.child_initializedField: string); // Error: number ~> string
|
||||
(Child.child_initializedField: string);
|
||||
(Child.child_initializedField: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized fields can reference `this`.
|
||||
*/
|
||||
(o.base_initializedFieldWithThis: number);
|
||||
(o.base_initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Child.base_initializedFieldWithThis: string);
|
||||
(Child.base_initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
(o.child_initializedFieldWithThis: number);
|
||||
(o.child_initializedFieldWithThis: string); // Error: number ~> string
|
||||
(Child.child_initializedFieldWithThis: string);
|
||||
(Child.child_initializedFieldWithThis: number); // Error: string ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields take the type of the annotation.
|
||||
* (Note that this matters when the annotation is more general than the type of
|
||||
* the initializer)
|
||||
*/
|
||||
(o.base_annotatedInitializedFieldValid: ?number);
|
||||
(o.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Child.base_annotatedInitializedFieldValid: ?number);
|
||||
(Child.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
(o.child_annotatedInitializedFieldValid: ?number);
|
||||
(o.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
(Child.child_annotatedInitializedFieldValid: ?number);
|
||||
(Child.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number
|
||||
|
||||
/**
|
||||
* Initialized + annotated fields where the init/annot combo is a mismatch
|
||||
* should assume the type of the annotation.
|
||||
*
|
||||
* (This happens in addition to erroring at the site of initialization)
|
||||
*/
|
||||
(o.base_annotatedInitializedFieldInvalid: number);
|
||||
(o.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Child.base_annotatedInitializedFieldInvalid: number);
|
||||
(Child.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
|
||||
(o.child_annotatedInitializedFieldInvalid: number);
|
||||
(o.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
(Child.child_annotatedInitializedFieldInvalid: number);
|
||||
(Child.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Derived fields without an initializer that shadow base fields *with* an
|
||||
* initializer should have the type of the base field.
|
||||
*/
|
||||
(o.inherited_initializer: number);
|
||||
(o.inherited_initializer: string); // Error: number ~> string
|
||||
(Child.inherited_initializer: number);
|
||||
(Child.inherited_initializer: string); // Error: number ~> string
|
|
@ -0,0 +1,31 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* Fields annotated with a generic should assume a type once the type param
|
||||
* is instantiated.
|
||||
*/
|
||||
class ClassAnnotated<T> {
|
||||
p: T;
|
||||
static p: T;
|
||||
}
|
||||
|
||||
var o1 = new ClassAnnotated();
|
||||
o1.p = 42;
|
||||
(o1.p: number);
|
||||
(o1.p: string); // Error: number ~> string
|
||||
ClassAnnotated.p = 42;
|
||||
(ClassAnnotated.p: number);
|
||||
(ClassAnnotated.p: string); // Error: number ~> string
|
||||
|
||||
|
||||
/**
|
||||
* It's always an error to initialized a generically-typed field with an
|
||||
* expression of any type other than the generic itself.
|
||||
*/
|
||||
class ClassGenericInitialized<T, U> {
|
||||
invalid: T = 42; // Error: number ~> Generic<T>
|
||||
valid: T = ((42:any):T);
|
||||
|
||||
static invalid: T = 42; // Error: number ~> Generic<T>
|
||||
static valid: T = ((42:any):T);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,40 @@
|
|||
// @flow
|
||||
|
||||
var someVar = 42;
|
||||
|
||||
class Foo {
|
||||
outer = someVar;
|
||||
selfTyped: Foo;
|
||||
selfTypedInit = new Foo();
|
||||
|
||||
static outer = someVar;
|
||||
static selfTyped: Foo;
|
||||
static selfTypedInit = new Foo();
|
||||
|
||||
constructor() {
|
||||
var someVar = 'asdf';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Field initializers execute in a scope immediately under the scope outside the
|
||||
* class definition.
|
||||
*/
|
||||
(new Foo().outer: number);
|
||||
(new Foo().outer: string); // Error: number ~> string
|
||||
(Foo.outer: number);
|
||||
(Foo.outer: string); // Error: number ~> string
|
||||
|
||||
/**
|
||||
* Field initializers should be able to refer to the class type in their type
|
||||
* annotations.
|
||||
*/
|
||||
(new Foo().selfTyped: Foo);
|
||||
(new Foo().selfTyped: number); // Error: Foo ~> number
|
||||
(Foo.selfTyped: Foo);
|
||||
(Foo.selfTyped: number); // Error: Foo ~> number
|
||||
|
||||
(new Foo().selfTypedInit: Foo);
|
||||
(new Foo().selfTypedInit: number); // Error: Foo ~> number
|
||||
(Foo.selfTypedInit: Foo);
|
||||
(Foo.selfTypedInit: number); // Error: Foo ~> number
|
|
@ -0,0 +1,46 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`class_method_default_parameters.js 1`] = `
|
||||
"class A {
|
||||
|
||||
b: string;
|
||||
|
||||
c(d = this.b) { // ok - can use \`this\` in function default parameter values
|
||||
|
||||
}
|
||||
|
||||
e() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
f(g = this.e()) { // ok - can use \`this\` in function default parameter values
|
||||
|
||||
}
|
||||
|
||||
h(i: number = this.b) { // error
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
class A {
|
||||
b: string;
|
||||
|
||||
c(d = this.b) {
|
||||
// ok - can use \`this\` in function default parameter values
|
||||
}
|
||||
|
||||
e() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
f(g = this.e()) {
|
||||
// ok - can use \`this\` in function default parameter values
|
||||
}
|
||||
|
||||
h(i: number = this.b) {
|
||||
// error
|
||||
}
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1,21 @@
|
|||
class A {
|
||||
|
||||
b: string;
|
||||
|
||||
c(d = this.b) { // ok - can use `this` in function default parameter values
|
||||
|
||||
}
|
||||
|
||||
e() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
f(g = this.e()) { // ok - can use `this` in function default parameter values
|
||||
|
||||
}
|
||||
|
||||
h(i: number = this.b) { // error
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -213,6 +213,21 @@ var alias2: Alias = _Alias.factory(); // error: bad pun
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`extends_any.js 1`] = `
|
||||
"const Base: any = class {}
|
||||
class Derived1 extends Base {}
|
||||
class Derived2 extends Derived1 {
|
||||
m() {}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
const Base: any = class {};
|
||||
class Derived1 extends Base {}
|
||||
class Derived2 extends Derived1 {
|
||||
m() {}
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`loc.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
const Base: any = class {}
|
||||
class Derived1 extends Base {}
|
||||
class Derived2 extends Derived1 {
|
||||
m() {}
|
||||
}
|
|
@ -9,7 +9,20 @@ class D {
|
|||
constructor():number { }
|
||||
}
|
||||
|
||||
module.exports = C;
|
||||
// the return type of a constructor overrides the type of the class
|
||||
declare class Bar<T> {}
|
||||
declare class Foo<T> {
|
||||
constructor<U>(iterable: U): Bar<U>;
|
||||
}
|
||||
(new Foo('x'): Bar<string>); // ok
|
||||
(new Foo(123): Bar<string>); // error, number !~> string
|
||||
|
||||
// also overrides when it returns a different specialization of the same class
|
||||
declare class Baz<T> {
|
||||
constructor<U>(iterable: U): Baz<U>;
|
||||
}
|
||||
(new Baz('x'): Baz<string>); // ok
|
||||
(new Baz(123): Baz<string>); // error, number !~> string
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
class C {
|
||||
constructor() {}
|
||||
|
@ -19,6 +32,19 @@ class D {
|
|||
constructor(): number {}
|
||||
}
|
||||
|
||||
module.exports = C;
|
||||
// the return type of a constructor overrides the type of the class
|
||||
declare class Bar<T> {}
|
||||
declare class Foo<T> {
|
||||
constructor<U>(iterable: U): Bar<U>
|
||||
}
|
||||
(new Foo(\\"x\\"): Bar<string>); // ok
|
||||
(new Foo(123): Bar<string>); // error, number !~> string
|
||||
|
||||
// also overrides when it returns a different specialization of the same class
|
||||
declare class Baz<T> {
|
||||
constructor<U>(iterable: U): Baz<U>
|
||||
}
|
||||
(new Baz(\\"x\\"): Baz<string>); // ok
|
||||
(new Baz(123): Baz<string>); // error, number !~> string
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -6,4 +6,17 @@ class D {
|
|||
constructor():number { }
|
||||
}
|
||||
|
||||
module.exports = C;
|
||||
// the return type of a constructor overrides the type of the class
|
||||
declare class Bar<T> {}
|
||||
declare class Foo<T> {
|
||||
constructor<U>(iterable: U): Bar<U>;
|
||||
}
|
||||
(new Foo('x'): Bar<string>); // ok
|
||||
(new Foo(123): Bar<string>); // error, number !~> string
|
||||
|
||||
// also overrides when it returns a different specialization of the same class
|
||||
declare class Baz<T> {
|
||||
constructor<U>(iterable: U): Baz<U>;
|
||||
}
|
||||
(new Baz('x'): Baz<string>); // ok
|
||||
(new Baz(123): Baz<string>); // error, number !~> string
|
||||
|
|
|
@ -6,6 +6,7 @@ exports[`nested_test.js 1`] = `
|
|||
var docblock = require('qux/docblock');
|
||||
var min = require('d3/min.js');
|
||||
var corge = require('qux/corge');
|
||||
var SomeOtherModule = require('SomeOtherModule');
|
||||
|
||||
// make sure we don't pick up non-header @providesModule
|
||||
// annotations - see node_modules/qux/docblock.js
|
||||
|
@ -14,12 +15,14 @@ var unreachable = require('annotation');
|
|||
(docblock.fun(): string);
|
||||
(min.fun(): string);
|
||||
(corge.fun(): string);
|
||||
(SomeOtherModule.fun(): string);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
var docblock = require(\\"qux/docblock\\");
|
||||
var min = require(\\"d3/min.js\\");
|
||||
var corge = require(\\"qux/corge\\");
|
||||
var SomeOtherModule = require(\\"SomeOtherModule\\");
|
||||
|
||||
// make sure we don't pick up non-header @providesModule
|
||||
// annotations - see node_modules/qux/docblock.js
|
||||
|
@ -28,5 +31,6 @@ var unreachable = require(\\"annotation\\");
|
|||
(docblock.fun(): string);
|
||||
(min.fun(): string);
|
||||
(corge.fun(): string);
|
||||
(SomeOtherModule.fun(): string);
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
var docblock = require('qux/docblock');
|
||||
var min = require('d3/min.js');
|
||||
var corge = require('qux/corge');
|
||||
var SomeOtherModule = require('SomeOtherModule');
|
||||
|
||||
// make sure we don't pick up non-header @providesModule
|
||||
// annotations - see node_modules/qux/docblock.js
|
||||
|
@ -11,3 +12,4 @@ var unreachable = require('annotation');
|
|||
(docblock.fun(): string);
|
||||
(min.fun(): string);
|
||||
(corge.fun(): string);
|
||||
(SomeOtherModule.fun(): string);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/* @flow */
|
||||
|
||||
class AImplementation {}
|
||||
export function foo(): AImplementation { return new AImplementation(); }
|
|
@ -0,0 +1,35 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`A.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
class AImplementation {}
|
||||
export function foo(): AImplementation { return new AImplementation(); }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
class AImplementation {}
|
||||
export function foo(): AImplementation {
|
||||
return new AImplementation();
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`index.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
var A = require('A');
|
||||
(A.foo(): boolean); // Error: Either AImplementation ~> boolean or ADefinition ~> boolean
|
||||
|
||||
var test = require('test');
|
||||
(test.foo(): boolean); // Error: Either TestImplementation ~> boolean or TestDefinition ~> boolean
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
var A = require(\\"A\\");
|
||||
(A.foo(): boolean); // Error: Either AImplementation ~> boolean or ADefinition ~> boolean
|
||||
|
||||
var test = require(\\"test\\");
|
||||
(test.foo(): boolean); // Error: Either TestImplementation ~> boolean or TestDefinition ~> boolean
|
||||
"
|
||||
`;
|
|
@ -0,0 +1,7 @@
|
|||
/* @flow */
|
||||
|
||||
var A = require('A');
|
||||
(A.foo(): boolean); // Error: Either AImplementation ~> boolean or ADefinition ~> boolean
|
||||
|
||||
var test = require('test');
|
||||
(test.foo(): boolean); // Error: Either TestImplementation ~> boolean or TestDefinition ~> boolean
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -2,11 +2,8 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
// TODO: adding an empty line should not be dropped.
|
||||
|
||||
declare module ModuleAliasFoo {
|
||||
declare type baz = number;
|
||||
declare type toz = string;
|
||||
declare function foo(bar : baz) : toz;
|
||||
}
|
||||
declare type Foo = string;
|
|
@ -1,31 +1,25 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`declare_module_type_alias.js 1`] = `
|
||||
exports[`DeclareModule_TypeAlias.js 1`] = `
|
||||
"/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
// TODO: adding an empty line should not be dropped.
|
||||
|
||||
declare module ModuleAliasFoo {
|
||||
declare type baz = number;
|
||||
declare type toz = string;
|
||||
declare function foo(bar : baz) : toz;
|
||||
}
|
||||
declare type Foo = string;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
// TODO: adding an empty line should not be dropped.
|
||||
|
||||
declare module ModuleAliasFoo {
|
||||
declare type baz = number;
|
||||
declare type toz = string;
|
||||
declare function foo(bar: baz): toz;
|
||||
}
|
||||
declare type Foo = string;
|
||||
"
|
||||
`;
|
||||
|
||||
|
|
|
@ -372,37 +372,6 @@ var cp2_err: string = others.childprop2; // Error: number ~> string
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`destructuring_param.js 1`] = `
|
||||
"function f(a, { b }) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Doesn't parse right now
|
||||
|
||||
// function g(a, { a }) {
|
||||
// return a;
|
||||
// }
|
||||
|
||||
// function h({ a, { b } }, { c }, { { d } }) {
|
||||
// return a + b + c + d;
|
||||
// }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
function f(a, { b }) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Doesn't parse right now
|
||||
|
||||
// function g(a, { a }) {
|
||||
// return a;
|
||||
// }
|
||||
|
||||
// function h({ a, { b } }, { c }, { { d } }) {
|
||||
// return a + b + c + d;
|
||||
// }
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`eager.js 1`] = `
|
||||
"var x;
|
||||
({x} = null); // error, property \`x\` can not be accessed on \`null\`
|
||||
|
@ -427,7 +396,6 @@ function tup_pattern<X>([ proj ] : [X]) {} // proj: X
|
|||
type Proj<X> = [X];
|
||||
function tup_pattern2<X>([ proj ] : Proj<X>) {} // proj: X
|
||||
|
||||
function rest_antipattern<T>(...t: T) {} // nonsense
|
||||
function rest_pattern<X>(...r: X[]) {} // r: X[]
|
||||
|
||||
function obj_rest_pattern<X>({ _, ...o } : { _: any, x: X }) { // o: { x: X }
|
||||
|
@ -460,7 +428,6 @@ function tup_pattern<X>([proj]: [X]) {} // proj: X
|
|||
type Proj<X> = [X];
|
||||
function tup_pattern2<X>([proj]: Proj<X>) {} // proj: X
|
||||
|
||||
function rest_antipattern<T>(...t: T) {} // nonsense
|
||||
function rest_pattern<X>(...r: X[]) {} // r: X[]
|
||||
|
||||
function obj_rest_pattern<X>({ _, ...o }: { _: any, x: X }) {
|
||||
|
@ -530,6 +497,31 @@ var { x: o } = o;
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`refinement_non_termination.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
function _([argArray]: Array<Value>) {
|
||||
if (argArray instanceof NullValue || argArray instanceof UndefinedValue) {
|
||||
}
|
||||
};
|
||||
|
||||
class Value { }
|
||||
class NullValue extends Value { }
|
||||
class UndefinedValue extends Value { }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
function _([argArray]: Array<Value>) {
|
||||
if (argArray instanceof NullValue || argArray instanceof UndefinedValue) {
|
||||
}
|
||||
}
|
||||
|
||||
class Value {}
|
||||
class NullValue extends Value {}
|
||||
class UndefinedValue extends Value {}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`string_lit.js 1`] = `
|
||||
"var { \\"key\\": val } = { key: \\"val\\" };
|
||||
(val: void); // error: string ~> void
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
function f(a, { b }) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Doesn't parse right now
|
||||
|
||||
// function g(a, { a }) {
|
||||
// return a;
|
||||
// }
|
||||
|
||||
// function h({ a, { b } }, { c }, { { d } }) {
|
||||
// return a + b + c + d;
|
||||
// }
|
|
@ -12,7 +12,6 @@ function tup_pattern<X>([ proj ] : [X]) {} // proj: X
|
|||
type Proj<X> = [X];
|
||||
function tup_pattern2<X>([ proj ] : Proj<X>) {} // proj: X
|
||||
|
||||
function rest_antipattern<T>(...t: T) {} // nonsense
|
||||
function rest_pattern<X>(...r: X[]) {} // r: X[]
|
||||
|
||||
function obj_rest_pattern<X>({ _, ...o } : { _: any, x: X }) { // o: { x: X }
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// @flow
|
||||
|
||||
function _([argArray]: Array<Value>) {
|
||||
if (argArray instanceof NullValue || argArray instanceof UndefinedValue) {
|
||||
}
|
||||
};
|
||||
|
||||
class Value { }
|
||||
class NullValue extends Value { }
|
||||
class UndefinedValue extends Value { }
|
|
@ -7,5 +7,6 @@ let tests = [
|
|||
(document.createElement('link'): HTMLLinkElement);
|
||||
(document.createElement('option'): HTMLOptionElement);
|
||||
(document.createElement('select'): HTMLSelectElement);
|
||||
(document.querySelector('select'): HTMLSelectElement | null);
|
||||
}
|
||||
];
|
||||
|
|
|
@ -64,6 +64,7 @@ let tests = [
|
|||
(document.createElement('link'): HTMLLinkElement);
|
||||
(document.createElement('option'): HTMLOptionElement);
|
||||
(document.createElement('select'): HTMLSelectElement);
|
||||
(document.querySelector('select'): HTMLSelectElement | null);
|
||||
}
|
||||
];
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -76,6 +77,7 @@ let tests = [
|
|||
(document.createElement(\\"link\\"): HTMLLinkElement);
|
||||
(document.createElement(\\"option\\"): HTMLOptionElement);
|
||||
(document.createElement(\\"select\\"): HTMLSelectElement);
|
||||
(document.querySelector(\\"select\\"): HTMLSelectElement | null);
|
||||
}
|
||||
];
|
||||
"
|
||||
|
@ -644,15 +646,15 @@ let tests = [
|
|||
function() {
|
||||
document.createNodeIterator(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid
|
||||
document.createNodeIterator(document.body, -1, node => 'accept'); // invalid
|
||||
document.createNodeIterator(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createNodeIterator(document.body, -1, { accept: node => 'accept' }); // invalid
|
||||
document.createNodeIterator(document.body, -1, { acceptNode: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createNodeIterator(document.body, -1, { acceptNode: node => 'accept' }); // invalid
|
||||
document.createNodeIterator(document.body, -1, {}); // invalid
|
||||
},
|
||||
function() {
|
||||
document.createTreeWalker(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid
|
||||
document.createTreeWalker(document.body, -1, node => 'accept'); // invalid
|
||||
document.createTreeWalker(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createTreeWalker(document.body, -1, { accept: node => 'accept' }); // invalid
|
||||
document.createTreeWalker(document.body, -1, { acceptNode: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createTreeWalker(document.body, -1, { acceptNode: node => 'accept' }); // invalid
|
||||
document.createTreeWalker(document.body, -1, {}); // invalid
|
||||
},
|
||||
];
|
||||
|
@ -849,10 +851,10 @@ let tests = [
|
|||
); // valid
|
||||
document.createNodeIterator(document.body, -1, node => \\"accept\\"); // invalid
|
||||
document.createNodeIterator(document.body, -1, {
|
||||
accept: node => NodeFilter.FILTER_ACCEPT
|
||||
acceptNode: node => NodeFilter.FILTER_ACCEPT
|
||||
}); // valid
|
||||
document.createNodeIterator(document.body, -1, {
|
||||
accept: node => \\"accept\\"
|
||||
acceptNode: node => \\"accept\\"
|
||||
}); // invalid
|
||||
document.createNodeIterator(document.body, -1, {}); // invalid
|
||||
},
|
||||
|
@ -864,9 +866,11 @@ let tests = [
|
|||
); // valid
|
||||
document.createTreeWalker(document.body, -1, node => \\"accept\\"); // invalid
|
||||
document.createTreeWalker(document.body, -1, {
|
||||
accept: node => NodeFilter.FILTER_ACCEPT
|
||||
acceptNode: node => NodeFilter.FILTER_ACCEPT
|
||||
}); // valid
|
||||
document.createTreeWalker(document.body, -1, { accept: node => \\"accept\\" }); // invalid
|
||||
document.createTreeWalker(document.body, -1, {
|
||||
acceptNode: node => \\"accept\\"
|
||||
}); // invalid
|
||||
document.createTreeWalker(document.body, -1, {}); // invalid
|
||||
}
|
||||
];
|
||||
|
|
|
@ -181,15 +181,15 @@ let tests = [
|
|||
function() {
|
||||
document.createNodeIterator(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid
|
||||
document.createNodeIterator(document.body, -1, node => 'accept'); // invalid
|
||||
document.createNodeIterator(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createNodeIterator(document.body, -1, { accept: node => 'accept' }); // invalid
|
||||
document.createNodeIterator(document.body, -1, { acceptNode: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createNodeIterator(document.body, -1, { acceptNode: node => 'accept' }); // invalid
|
||||
document.createNodeIterator(document.body, -1, {}); // invalid
|
||||
},
|
||||
function() {
|
||||
document.createTreeWalker(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid
|
||||
document.createTreeWalker(document.body, -1, node => 'accept'); // invalid
|
||||
document.createTreeWalker(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createTreeWalker(document.body, -1, { accept: node => 'accept' }); // invalid
|
||||
document.createTreeWalker(document.body, -1, { acceptNode: node => NodeFilter.FILTER_ACCEPT }); // valid
|
||||
document.createTreeWalker(document.body, -1, { acceptNode: node => 'accept' }); // invalid
|
||||
document.createTreeWalker(document.body, -1, {}); // invalid
|
||||
},
|
||||
];
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
class Foo {
|
||||
annotationOnly: string;
|
||||
initOnly = 'asdf'
|
||||
initWithAnnotation: string = 'asdf';
|
||||
[computed]: string;
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
annotationOnly: string;
|
||||
initOnly = \\"asdf\\";
|
||||
initWithAnnotation: string = \\"asdf\\";
|
||||
[computed]: string;
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,8 @@
|
|||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
annotationOnly: string;
|
||||
initOnly = 'asdf'
|
||||
initWithAnnotation: string = 'asdf';
|
||||
[computed]: string;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
class Foo {
|
||||
annotationOnly: string;
|
||||
initOnly = 'asdf';
|
||||
initWithAnnotation: string = 'asdf';
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
annotationOnly: string;
|
||||
initOnly = \\"asdf\\";
|
||||
initWithAnnotation: string = \\"asdf\\";
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,7 @@
|
|||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
annotationOnly: string;
|
||||
initOnly = 'asdf';
|
||||
initWithAnnotation: string = 'asdf';
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
class Foo {
|
||||
static annotationOnly: string;
|
||||
static initOnly = 'asdf';
|
||||
static initWithAnnotation: string = 'asdf';
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
static annotationOnly: string;
|
||||
static initOnly = \\"asdf\\";
|
||||
static initWithAnnotation: string = \\"asdf\\";
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,7 @@
|
|||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
static annotationOnly: string;
|
||||
static initOnly = 'asdf';
|
||||
static initWithAnnotation: string = 'asdf';
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
class Foo {
|
||||
static annotationOnly: string;
|
||||
static initOnly = 'asdf';
|
||||
static initWithAnnotation: string = 'asdf';
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
static annotationOnly: string;
|
||||
static initOnly = \\"asdf\\";
|
||||
static initWithAnnotation: string = \\"asdf\\";
|
||||
}
|
||||
"
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,7 @@
|
|||
/* @flow */
|
||||
|
||||
class Foo {
|
||||
static annotationOnly: string;
|
||||
static initOnly = 'asdf';
|
||||
static initWithAnnotation: string = 'asdf';
|
||||
}
|
|
@ -35,3 +35,14 @@ export var str = \\"asdf\\";
|
|||
export var num = 42;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
export * as source from \\"./source\\";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
export * as source from \\"./source\\";
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export * as source from "./source";
|
|
@ -35,3 +35,14 @@ export var str = \\"asdf\\";
|
|||
export var num = 42;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
export * as source from \\"./source\\";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
export * as source from \\"./source\\";
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export * as source from "./source";
|
|
@ -0,0 +1,12 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"/* @flow */
|
||||
|
||||
export * as foo from \\"./test\\";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
|
||||
export * as foo from \\"./test\\";
|
||||
"
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,3 @@
|
|||
/* @flow */
|
||||
|
||||
export * as foo from "./test";
|
|
@ -134,7 +134,30 @@ const h: Request = new Request('http://example.org', {
|
|||
cache: 'default'
|
||||
}) // correct
|
||||
|
||||
var bodyUsed: boolean = h.bodyUsed;
|
||||
|
||||
h.text().then((t: string) => t); // correct
|
||||
h.text().then((t: Buffer) => t); // incorrect
|
||||
h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct
|
||||
h.arrayBuffer().then((ab: Buffer) => ab); // incorrect
|
||||
|
||||
const i: Request = new Request('http://example.org', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream'
|
||||
},
|
||||
body: new ArrayBuffer(10),
|
||||
}); // correct
|
||||
|
||||
const j: Request = new Request('http://example.org', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream'
|
||||
},
|
||||
body: new Uint8Array(10),
|
||||
}); // correct
|
||||
|
||||
const k: Request = new Request('http://example.org', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'image/jpeg'
|
||||
|
@ -144,14 +167,14 @@ const i: Request = new Request('http://example.org', {
|
|||
cache: 'default'
|
||||
}) // correct
|
||||
|
||||
const j: Request = new Request('http://example.org', {
|
||||
const l: Request = new Request('http://example.org', {
|
||||
method: 'GET',
|
||||
headers: 'Content-Type: image/jpeg',
|
||||
mode: 'cors',
|
||||
cache: 'default'
|
||||
}) // incorrect - headers is string
|
||||
|
||||
const k: Request = new Request('http://example.org', {
|
||||
const m: Request = new Request('http://example.org', {
|
||||
method: 'CONNECT',
|
||||
headers: {
|
||||
'Content-Type': 'image/jpeg'
|
||||
|
@ -159,13 +182,6 @@ const k: Request = new Request('http://example.org', {
|
|||
mode: 'cors',
|
||||
cache: 'default'
|
||||
}) // incorrect - CONNECT is forbidden
|
||||
|
||||
var l: boolean = h.bodyUsed;
|
||||
|
||||
h.text().then((t: string) => t); // correct
|
||||
h.text().then((t: Buffer) => t); // incorrect
|
||||
h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct
|
||||
h.arrayBuffer().then((ab: Buffer) => ab); // incorrect
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* @flow */
|
||||
const a: Request = new Request(); // incorrect
|
||||
|
@ -186,7 +202,30 @@ const h: Request = new Request(\\"http://example.org\\", {
|
|||
cache: \\"default\\"
|
||||
}); // correct
|
||||
|
||||
var bodyUsed: boolean = h.bodyUsed;
|
||||
|
||||
h.text().then((t: string) => t); // correct
|
||||
h.text().then((t: Buffer) => t); // incorrect
|
||||
h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct
|
||||
h.arrayBuffer().then((ab: Buffer) => ab); // incorrect
|
||||
|
||||
const i: Request = new Request(\\"http://example.org\\", {
|
||||
method: \\"POST\\",
|
||||
headers: {
|
||||
\\"Content-Type\\": \\"application/octet-stream\\"
|
||||
},
|
||||
body: new ArrayBuffer(10)
|
||||
}); // correct
|
||||
|
||||
const j: Request = new Request(\\"http://example.org\\", {
|
||||
method: \\"POST\\",
|
||||
headers: {
|
||||
\\"Content-Type\\": \\"application/octet-stream\\"
|
||||
},
|
||||
body: new Uint8Array(10)
|
||||
}); // correct
|
||||
|
||||
const k: Request = new Request(\\"http://example.org\\", {
|
||||
method: \\"POST\\",
|
||||
headers: {
|
||||
\\"Content-Type\\": \\"image/jpeg\\"
|
||||
|
@ -196,14 +235,14 @@ const i: Request = new Request(\\"http://example.org\\", {
|
|||
cache: \\"default\\"
|
||||
}); // correct
|
||||
|
||||
const j: Request = new Request(\\"http://example.org\\", {
|
||||
const l: Request = new Request(\\"http://example.org\\", {
|
||||
method: \\"GET\\",
|
||||
headers: \\"Content-Type: image/jpeg\\",
|
||||
mode: \\"cors\\",
|
||||
cache: \\"default\\"
|
||||
}); // incorrect - headers is string
|
||||
|
||||
const k: Request = new Request(\\"http://example.org\\", {
|
||||
const m: Request = new Request(\\"http://example.org\\", {
|
||||
method: \\"CONNECT\\",
|
||||
headers: {
|
||||
\\"Content-Type\\": \\"image/jpeg\\"
|
||||
|
@ -211,13 +250,6 @@ const k: Request = new Request(\\"http://example.org\\", {
|
|||
mode: \\"cors\\",
|
||||
cache: \\"default\\"
|
||||
}); // incorrect - CONNECT is forbidden
|
||||
|
||||
var l: boolean = h.bodyUsed;
|
||||
|
||||
h.text().then((t: string) => t); // correct
|
||||
h.text().then((t: Buffer) => t); // incorrect
|
||||
h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct
|
||||
h.arrayBuffer().then((ab: Buffer) => ab); // incorrect
|
||||
"
|
||||
`;
|
||||
|
||||
|
|
|
@ -17,7 +17,30 @@ const h: Request = new Request('http://example.org', {
|
|||
cache: 'default'
|
||||
}) // correct
|
||||
|
||||
var bodyUsed: boolean = h.bodyUsed;
|
||||
|
||||
h.text().then((t: string) => t); // correct
|
||||
h.text().then((t: Buffer) => t); // incorrect
|
||||
h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct
|
||||
h.arrayBuffer().then((ab: Buffer) => ab); // incorrect
|
||||
|
||||
const i: Request = new Request('http://example.org', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream'
|
||||
},
|
||||
body: new ArrayBuffer(10),
|
||||
}); // correct
|
||||
|
||||
const j: Request = new Request('http://example.org', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream'
|
||||
},
|
||||
body: new Uint8Array(10),
|
||||
}); // correct
|
||||
|
||||
const k: Request = new Request('http://example.org', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'image/jpeg'
|
||||
|
@ -27,14 +50,14 @@ const i: Request = new Request('http://example.org', {
|
|||
cache: 'default'
|
||||
}) // correct
|
||||
|
||||
const j: Request = new Request('http://example.org', {
|
||||
const l: Request = new Request('http://example.org', {
|
||||
method: 'GET',
|
||||
headers: 'Content-Type: image/jpeg',
|
||||
mode: 'cors',
|
||||
cache: 'default'
|
||||
}) // incorrect - headers is string
|
||||
|
||||
const k: Request = new Request('http://example.org', {
|
||||
const m: Request = new Request('http://example.org', {
|
||||
method: 'CONNECT',
|
||||
headers: {
|
||||
'Content-Type': 'image/jpeg'
|
||||
|
@ -42,10 +65,3 @@ const k: Request = new Request('http://example.org', {
|
|||
mode: 'cors',
|
||||
cache: 'default'
|
||||
}) // incorrect - CONNECT is forbidden
|
||||
|
||||
var l: boolean = h.bodyUsed;
|
||||
|
||||
h.text().then((t: string) => t); // correct
|
||||
h.text().then((t: Buffer) => t); // incorrect
|
||||
h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct
|
||||
h.arrayBuffer().then((ab: Buffer) => ab); // incorrect
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`a.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
(require('./b'): number);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
(require(\\"./b\\"): number);
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`b.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
module.exports = \\"\\";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
module.exports = \\"\\";
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`test.js 1`] = `
|
||||
"// @flow
|
||||
|
||||
(\\"\\": number);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
(\\"\\": number);
|
||||
"
|
||||
`;
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
(require('./b'): number);
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
module.exports = "";
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
("": number);
|
|
@ -11,8 +11,8 @@ test.apply(\\"\\", [\\"\\", 0]);
|
|||
// wrong this is an error
|
||||
test.apply(0, [\\"\\", 0]); // error: lookup \`length\` on Number
|
||||
|
||||
// not enough arguments is an error (via incompatible RestT)
|
||||
test.apply(\\"\\", [\\"\\"]); // error: string ~> number
|
||||
// not enough arguments is an error
|
||||
test.apply(\\"\\", [\\"\\"]); // error: void ~> number
|
||||
|
||||
// mistyped arguments is an error
|
||||
test.apply(\\"\\", [\\"\\", \\"\\"]); // error: string ~> number (2nd arg)
|
||||
|
@ -43,6 +43,12 @@ test.apply(\\"\\", \\"not array\\"); // error: expect array of args
|
|||
function test2(): number { return 0; }
|
||||
(test2.apply(): number);
|
||||
(test2.apply(\\"\\"): number);
|
||||
|
||||
// callable objects
|
||||
function test3(x: { (a: string, b: string): void }) {
|
||||
x.apply(x, ['foo', 'bar']); // ok
|
||||
x.apply(x, ['foo', 123]); // error, number !~> string
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
function test(a: string, b: number): number {
|
||||
return this.length; // expect []/\\"\\" this
|
||||
|
@ -54,8 +60,8 @@ test.apply(\\"\\", [\\"\\", 0]);
|
|||
// wrong this is an error
|
||||
test.apply(0, [\\"\\", 0]); // error: lookup \`length\` on Number
|
||||
|
||||
// not enough arguments is an error (via incompatible RestT)
|
||||
test.apply(\\"\\", [\\"\\"]); // error: string ~> number
|
||||
// not enough arguments is an error
|
||||
test.apply(\\"\\", [\\"\\"]); // error: void ~> number
|
||||
|
||||
// mistyped arguments is an error
|
||||
test.apply(\\"\\", [\\"\\", \\"\\"]); // error: string ~> number (2nd arg)
|
||||
|
@ -90,6 +96,12 @@ function test2(): number {
|
|||
}
|
||||
(test2.apply(): number);
|
||||
(test2.apply(\\"\\"): number);
|
||||
|
||||
// callable objects
|
||||
function test3(x: { (a: string, b: string): void }) {
|
||||
x.apply(x, [\\"foo\\", \\"bar\\"]); // ok
|
||||
x.apply(x, [\\"foo\\", 123]); // error, number !~> string
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
|
@ -102,6 +114,25 @@ let tests = [
|
|||
y('bar'); // ok
|
||||
y(123); // error, number !~> string
|
||||
},
|
||||
|
||||
// callable objects
|
||||
function(x: { (a: string, b: string): void }) {
|
||||
let y = x.bind(x, 'foo');
|
||||
y('bar'); // ok
|
||||
y(123); // error, number !~> string
|
||||
},
|
||||
|
||||
// non-callable objects
|
||||
function(x: { a: string }) {
|
||||
x.bind(x, 'foo'); // error
|
||||
},
|
||||
|
||||
// callable objects with overridden \`bind\` method
|
||||
function(x: {(a: string, b: string): void, bind(a: string): void}) {
|
||||
(x.bind('foo'): void); // ok
|
||||
(x.bind(123): void); // error, number !~> string
|
||||
},
|
||||
|
||||
];
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
@ -111,6 +142,24 @@ let tests = [
|
|||
let y = x.bind(x, \\"foo\\");
|
||||
y(\\"bar\\"); // ok
|
||||
y(123); // error, number !~> string
|
||||
},
|
||||
|
||||
// callable objects
|
||||
function(x: { (a: string, b: string): void }) {
|
||||
let y = x.bind(x, \\"foo\\");
|
||||
y(\\"bar\\"); // ok
|
||||
y(123); // error, number !~> string
|
||||
},
|
||||
|
||||
// non-callable objects
|
||||
function(x: { a: string }) {
|
||||
x.bind(x, \\"foo\\"); // error
|
||||
},
|
||||
|
||||
// callable objects with overridden \`bind\` method
|
||||
function(x: { (a: string, b: string): void, bind(a: string): void }) {
|
||||
(x.bind(\\"foo\\"): void); // ok
|
||||
(x.bind(123): void); // error, number !~> string
|
||||
}
|
||||
];
|
||||
"
|
||||
|
@ -129,8 +178,8 @@ test.call(\\"\\", \\"\\", 0);
|
|||
// wrong this is an error
|
||||
test.call(0, \\"\\", 0); // error: lookup \`length\` on Number
|
||||
|
||||
// not enough arguments is an error (via incompatible RestT)
|
||||
test.call(\\"\\", \\"\\"); // error: string ~> number
|
||||
// not enough arguments is an error
|
||||
test.call(\\"\\", \\"\\"); // error: void ~> number
|
||||
|
||||
// mistyped arguments is an error
|
||||
test.call(\\"\\", \\"\\", \\"\\"); // error: string ~> number (2nd arg)
|
||||
|
@ -152,6 +201,12 @@ f([0, 0]); // error: number ~> string (1st arg)
|
|||
function test2(): number { return 0; }
|
||||
(test2.call(): number);
|
||||
(test2.call(\\"\\"): number);
|
||||
|
||||
// callable objects
|
||||
function test3(x: { (a: string, b: string): void }) {
|
||||
x.call(x, 'foo', 'bar'); // ok
|
||||
x.call(x, 'foo', 123); // error, number !~> string
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @flow
|
||||
|
||||
|
@ -165,8 +220,8 @@ test.call(\\"\\", \\"\\", 0);
|
|||
// wrong this is an error
|
||||
test.call(0, \\"\\", 0); // error: lookup \`length\` on Number
|
||||
|
||||
// not enough arguments is an error (via incompatible RestT)
|
||||
test.call(\\"\\", \\"\\"); // error: string ~> number
|
||||
// not enough arguments is an error
|
||||
test.call(\\"\\", \\"\\"); // error: void ~> number
|
||||
|
||||
// mistyped arguments is an error
|
||||
test.call(\\"\\", \\"\\", \\"\\"); // error: string ~> number (2nd arg)
|
||||
|
@ -192,6 +247,12 @@ function test2(): number {
|
|||
}
|
||||
(test2.call(): number);
|
||||
(test2.call(\\"\\"): number);
|
||||
|
||||
// callable objects
|
||||
function test3(x: { (a: string, b: string): void }) {
|
||||
x.call(x, \\"foo\\", \\"bar\\"); // ok
|
||||
x.call(x, \\"foo\\", 123); // error, number !~> string
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
|
@ -337,42 +398,202 @@ var e = (d.bind(1): Function)();
|
|||
exports[`rest.js 1`] = `
|
||||
"/* regression tests */
|
||||
|
||||
function rest_array<T>(...xs: Array<T>): T {
|
||||
function rest_array<T>(...xs: Array<T>): T { // Ok, arrays can be rest params
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// Warn, singleton tuple types don't represent rest params
|
||||
function rest_tuple<T>(...xs: [T]): T {
|
||||
function rest_tuple<T>(...xs: [T]): T { // Ok, tuples can be rest params
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_any(...xs: any): any {
|
||||
function rest_ro_array<T>(...xs: $ReadOnlyArray<T>): T { // Ok
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// Warn, arbitrary subtypes of an array type don't represent rest params
|
||||
function rest_t<U, T: Array<U>>(...xs: T): U {
|
||||
function rest_any(...xs: any): any { // Ok, any can be a rest param
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_t<U, T: Array<U>>(...xs: T): U { // Ok, bounded targ can be rest
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// These are ok bounds for the rest param
|
||||
function unbound_rest_t<T>(...xs: T): void {}
|
||||
function mixed_rest_t<T: mixed>(...xs: T): void {}
|
||||
function array_rest_t<T: Array<mixed>>(...xs: T): void {}
|
||||
function roarray_rest_t<T: $ReadOnlyArray<mixed>>(...xs: T): void {}
|
||||
function iterable_rest_t<T: Iterable<mixed>>(...xs: T): void {}
|
||||
function empty_rest_t<T: empty>(...xs: T): void {}
|
||||
function bounds_on_bounds<T>() {
|
||||
return function<U: T>(...xs: T): void {}
|
||||
}
|
||||
|
||||
// These are bad bounds for the rest param
|
||||
function bad_unbound_rest_t<T>(...xs: T): T {
|
||||
return xs.pop(); // Error - no bound on T
|
||||
}
|
||||
function string_rest_t<T: string>(...xs: T): void {} // Error - rest param can't be a string
|
||||
function empty_rest_t<T: empty>(...xs: T): void {} // Error - rest param can't be empty
|
||||
|
||||
type Rest = Array<string>;
|
||||
function rest_alias(...xs: Rest): void {} // Ok
|
||||
|
||||
function rest_union(...xs: [1,2] | Array<number>): number { // OK
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_intersection(...xs: { x: number } & [1,2]): number { // OK
|
||||
return xs[0] + xs.x;
|
||||
}
|
||||
|
||||
function empty_rest<T:Array<mixed>>(...xs: T): T { return xs; }
|
||||
(empty_rest(): empty); // Error Array ~> empty
|
||||
|
||||
function return_rest_param<Args:Array<mixed>>(
|
||||
f: (...args: Args) => void,
|
||||
): (...args: Args) => number {
|
||||
return function(...args) {
|
||||
return args; // Error: Array ~> number
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* regression tests */
|
||||
|
||||
function rest_array<T>(...xs: Array<T>): T {
|
||||
// Ok, arrays can be rest params
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// Warn, singleton tuple types don't represent rest params
|
||||
function rest_tuple<T>(...xs: [T]): T {
|
||||
// Ok, tuples can be rest params
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_ro_array<T>(...xs: $ReadOnlyArray<T>): T {
|
||||
// Ok
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_any(...xs: any): any {
|
||||
// Ok, any can be a rest param
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// Warn, arbitrary subtypes of an array type don't represent rest params
|
||||
function rest_t<U, T: Array<U>>(...xs: T): U {
|
||||
// Ok, bounded targ can be rest
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// These are ok bounds for the rest param
|
||||
function unbound_rest_t<T>(...xs: T): void {}
|
||||
function mixed_rest_t<T: mixed>(...xs: T): void {}
|
||||
function array_rest_t<T: Array<mixed>>(...xs: T): void {}
|
||||
function roarray_rest_t<T: $ReadOnlyArray<mixed>>(...xs: T): void {}
|
||||
function iterable_rest_t<T: Iterable<mixed>>(...xs: T): void {}
|
||||
function empty_rest_t<T: empty>(...xs: T): void {}
|
||||
function bounds_on_bounds<T>() {
|
||||
return function<U: T>(...xs: T): void {};
|
||||
}
|
||||
|
||||
// These are bad bounds for the rest param
|
||||
function bad_unbound_rest_t<T>(...xs: T): T {
|
||||
return xs.pop(); // Error - no bound on T
|
||||
}
|
||||
function string_rest_t<T: string>(...xs: T): void {} // Error - rest param can't be a string
|
||||
function empty_rest_t<T: empty>(...xs: T): void {} // Error - rest param can't be empty
|
||||
|
||||
type Rest = Array<string>;
|
||||
function rest_alias(...xs: Rest): void {} // Ok
|
||||
|
||||
function rest_union(...xs: [1, 2] | Array<number>): number {
|
||||
// OK
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_intersection(...xs: { x: number } & [1, 2]): number {
|
||||
// OK
|
||||
return xs[0] + xs.x;
|
||||
}
|
||||
|
||||
function empty_rest<T: Array<mixed>>(...xs: T): T {
|
||||
return xs;
|
||||
}
|
||||
(empty_rest(): empty); // Error Array ~> empty
|
||||
|
||||
function return_rest_param<Args: Array<mixed>>(
|
||||
f: (...args: Args) => void
|
||||
): (...args: Args) => number {
|
||||
return function(...args) {
|
||||
return args; // Error: Array ~> number
|
||||
};
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`rest_type.js 1`] = `
|
||||
"/* regression tests */
|
||||
|
||||
type rest_array = <T>(...xs: Array<T>) => T; // Ok, arrays can be rest params
|
||||
|
||||
type rest_tuple = <T>(...xs: [T]) => T; // Ok, tuples can be rest params
|
||||
|
||||
type rest_ro_array = <T>(...xs: $ReadOnlyArray<T>) => T; // Ok
|
||||
|
||||
type rest_any = (...xs: any) => any; // Ok, any can be a rest param
|
||||
|
||||
type rest_t = <U, T: Array<U>>(...xs: T) => U; // Ok, bounded targ can be rest
|
||||
|
||||
type unbound_rest_t = <T>(...xs: T) => void; // Should be error but no way to check yet :(
|
||||
function test_unbound_rest(f: <T>(x: T, ...xs: T) => void) {
|
||||
f(123); // Error - number ~> array - luckily this errors
|
||||
}
|
||||
|
||||
type string_rest_t = (...xs: string) => void; // Should be error but no way to check yet :(
|
||||
function test_string_rest(f: string_rest_t) {
|
||||
f('hello'); // Error - string ~> array - luckily this errors
|
||||
}
|
||||
|
||||
type Rest = Array<string>;
|
||||
type rest_alias = (...xs: Rest) => void; // Ok
|
||||
|
||||
type rest_union = (...xs: [1,2] | Array<number>) => number; // OK
|
||||
|
||||
type rest_intersection = (...xs: { x: number } & [1,2]) => number; // OK
|
||||
|
||||
type empty_rest = <T:Array<mixed>>(...xs: T) => T; // OK
|
||||
((f: empty_rest) => (f(): empty)); // Error Array ~> empty
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/* regression tests */
|
||||
|
||||
type rest_array = <T>(...xs: Array<T>) => T; // Ok, arrays can be rest params
|
||||
|
||||
type rest_tuple = <T>(...xs: [T]) => T; // Ok, tuples can be rest params
|
||||
|
||||
type rest_ro_array = <T>(...xs: $ReadOnlyArray<T>) => T; // Ok
|
||||
|
||||
type rest_any = (...xs: any) => any; // Ok, any can be a rest param
|
||||
|
||||
type rest_t = <U, T: Array<U>>(...xs: T) => U; // Ok, bounded targ can be rest
|
||||
|
||||
type unbound_rest_t = <T>(...xs: T) => void; // Should be error but no way to check yet :(
|
||||
function test_unbound_rest(f: <T>(x: T, ...xs: T) => void) {
|
||||
f(123); // Error - number ~> array - luckily this errors
|
||||
}
|
||||
|
||||
type string_rest_t = (...xs: string) => void; // Should be error but no way to check yet :(
|
||||
function test_string_rest(f: string_rest_t) {
|
||||
f(\\"hello\\"); // Error - string ~> array - luckily this errors
|
||||
}
|
||||
|
||||
type Rest = Array<string>;
|
||||
type rest_alias = (...xs: Rest) => void; // Ok
|
||||
|
||||
type rest_union = (...xs: [1, 2] | Array<number>) => number; // OK
|
||||
|
||||
type rest_intersection = (...xs: { x: number } & [1, 2]) => number; // OK
|
||||
|
||||
type empty_rest = <T: Array<mixed>>(...xs: T) => T; // OK
|
||||
(f: empty_rest) => (f(): empty); // Error Array ~> empty
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -8,8 +8,8 @@ test.apply("", ["", 0]);
|
|||
// wrong this is an error
|
||||
test.apply(0, ["", 0]); // error: lookup `length` on Number
|
||||
|
||||
// not enough arguments is an error (via incompatible RestT)
|
||||
test.apply("", [""]); // error: string ~> number
|
||||
// not enough arguments is an error
|
||||
test.apply("", [""]); // error: void ~> number
|
||||
|
||||
// mistyped arguments is an error
|
||||
test.apply("", ["", ""]); // error: string ~> number (2nd arg)
|
||||
|
@ -40,3 +40,9 @@ test.apply("", "not array"); // error: expect array of args
|
|||
function test2(): number { return 0; }
|
||||
(test2.apply(): number);
|
||||
(test2.apply(""): number);
|
||||
|
||||
// callable objects
|
||||
function test3(x: { (a: string, b: string): void }) {
|
||||
x.apply(x, ['foo', 'bar']); // ok
|
||||
x.apply(x, ['foo', 123]); // error, number !~> string
|
||||
}
|
||||
|
|
|
@ -6,4 +6,23 @@ let tests = [
|
|||
y('bar'); // ok
|
||||
y(123); // error, number !~> string
|
||||
},
|
||||
|
||||
// callable objects
|
||||
function(x: { (a: string, b: string): void }) {
|
||||
let y = x.bind(x, 'foo');
|
||||
y('bar'); // ok
|
||||
y(123); // error, number !~> string
|
||||
},
|
||||
|
||||
// non-callable objects
|
||||
function(x: { a: string }) {
|
||||
x.bind(x, 'foo'); // error
|
||||
},
|
||||
|
||||
// callable objects with overridden `bind` method
|
||||
function(x: {(a: string, b: string): void, bind(a: string): void}) {
|
||||
(x.bind('foo'): void); // ok
|
||||
(x.bind(123): void); // error, number !~> string
|
||||
},
|
||||
|
||||
];
|
||||
|
|
|
@ -10,8 +10,8 @@ test.call("", "", 0);
|
|||
// wrong this is an error
|
||||
test.call(0, "", 0); // error: lookup `length` on Number
|
||||
|
||||
// not enough arguments is an error (via incompatible RestT)
|
||||
test.call("", ""); // error: string ~> number
|
||||
// not enough arguments is an error
|
||||
test.call("", ""); // error: void ~> number
|
||||
|
||||
// mistyped arguments is an error
|
||||
test.call("", "", ""); // error: string ~> number (2nd arg)
|
||||
|
@ -33,3 +33,9 @@ f([0, 0]); // error: number ~> string (1st arg)
|
|||
function test2(): number { return 0; }
|
||||
(test2.call(): number);
|
||||
(test2.call(""): number);
|
||||
|
||||
// callable objects
|
||||
function test3(x: { (a: string, b: string): void }) {
|
||||
x.call(x, 'foo', 'bar'); // ok
|
||||
x.call(x, 'foo', 123); // error, number !~> string
|
||||
}
|
||||
|
|
|
@ -1,19 +1,61 @@
|
|||
/* regression tests */
|
||||
|
||||
function rest_array<T>(...xs: Array<T>): T {
|
||||
function rest_array<T>(...xs: Array<T>): T { // Ok, arrays can be rest params
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// Warn, singleton tuple types don't represent rest params
|
||||
function rest_tuple<T>(...xs: [T]): T {
|
||||
function rest_tuple<T>(...xs: [T]): T { // Ok, tuples can be rest params
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_any(...xs: any): any {
|
||||
function rest_ro_array<T>(...xs: $ReadOnlyArray<T>): T { // Ok
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// Warn, arbitrary subtypes of an array type don't represent rest params
|
||||
function rest_t<U, T: Array<U>>(...xs: T): U {
|
||||
function rest_any(...xs: any): any { // Ok, any can be a rest param
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_t<U, T: Array<U>>(...xs: T): U { // Ok, bounded targ can be rest
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
// These are ok bounds for the rest param
|
||||
function unbound_rest_t<T>(...xs: T): void {}
|
||||
function mixed_rest_t<T: mixed>(...xs: T): void {}
|
||||
function array_rest_t<T: Array<mixed>>(...xs: T): void {}
|
||||
function roarray_rest_t<T: $ReadOnlyArray<mixed>>(...xs: T): void {}
|
||||
function iterable_rest_t<T: Iterable<mixed>>(...xs: T): void {}
|
||||
function empty_rest_t<T: empty>(...xs: T): void {}
|
||||
function bounds_on_bounds<T>() {
|
||||
return function<U: T>(...xs: T): void {}
|
||||
}
|
||||
|
||||
// These are bad bounds for the rest param
|
||||
function bad_unbound_rest_t<T>(...xs: T): T {
|
||||
return xs.pop(); // Error - no bound on T
|
||||
}
|
||||
function string_rest_t<T: string>(...xs: T): void {} // Error - rest param can't be a string
|
||||
function empty_rest_t<T: empty>(...xs: T): void {} // Error - rest param can't be empty
|
||||
|
||||
type Rest = Array<string>;
|
||||
function rest_alias(...xs: Rest): void {} // Ok
|
||||
|
||||
function rest_union(...xs: [1,2] | Array<number>): number { // OK
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
function rest_intersection(...xs: { x: number } & [1,2]): number { // OK
|
||||
return xs[0] + xs.x;
|
||||
}
|
||||
|
||||
function empty_rest<T:Array<mixed>>(...xs: T): T { return xs; }
|
||||
(empty_rest(): empty); // Error Array ~> empty
|
||||
|
||||
function return_rest_param<Args:Array<mixed>>(
|
||||
f: (...args: Args) => void,
|
||||
): (...args: Args) => number {
|
||||
return function(...args) {
|
||||
return args; // Error: Array ~> number
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* regression tests */
|
||||
|
||||
type rest_array = <T>(...xs: Array<T>) => T; // Ok, arrays can be rest params
|
||||
|
||||
type rest_tuple = <T>(...xs: [T]) => T; // Ok, tuples can be rest params
|
||||
|
||||
type rest_ro_array = <T>(...xs: $ReadOnlyArray<T>) => T; // Ok
|
||||
|
||||
type rest_any = (...xs: any) => any; // Ok, any can be a rest param
|
||||
|
||||
type rest_t = <U, T: Array<U>>(...xs: T) => U; // Ok, bounded targ can be rest
|
||||
|
||||
type unbound_rest_t = <T>(...xs: T) => void; // Should be error but no way to check yet :(
|
||||
function test_unbound_rest(f: <T>(x: T, ...xs: T) => void) {
|
||||
f(123); // Error - number ~> array - luckily this errors
|
||||
}
|
||||
|
||||
type string_rest_t = (...xs: string) => void; // Should be error but no way to check yet :(
|
||||
function test_string_rest(f: string_rest_t) {
|
||||
f('hello'); // Error - string ~> array - luckily this errors
|
||||
}
|
||||
|
||||
type Rest = Array<string>;
|
||||
type rest_alias = (...xs: Rest) => void; // Ok
|
||||
|
||||
type rest_union = (...xs: [1,2] | Array<number>) => number; // OK
|
||||
|
||||
type rest_intersection = (...xs: { x: number } & [1,2]) => number; // OK
|
||||
|
||||
type empty_rest = <T:Array<mixed>>(...xs: T) => T; // OK
|
||||
((f: empty_rest) => (f(): empty)); // Error Array ~> empty
|
|
@ -577,6 +577,73 @@ if (multiple_return_result.done) {
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`refi.js 1`] = `
|
||||
"function *a(x: {a: void | string}): Generator<void, void, void> {
|
||||
if (!x.a) return;
|
||||
(x.a: string); // ok
|
||||
yield;
|
||||
(x.a: string); // error
|
||||
}
|
||||
|
||||
function *b(x: void | string): Generator<void, void, void> {
|
||||
if (!x) return;
|
||||
(x: string); // ok
|
||||
yield;
|
||||
(x: string); // ok
|
||||
}
|
||||
|
||||
declare function fn(): Generator<void, void, void>;
|
||||
|
||||
function *c(x: {a: void | string}): Generator<void, void, void> {
|
||||
const gen = fn();
|
||||
if (!x.a) return;
|
||||
(x.a: string); // ok
|
||||
yield * gen;
|
||||
(x.a: string); // error
|
||||
}
|
||||
|
||||
function *d(x: void | string): Generator<void, void, void> {
|
||||
const gen = fn();
|
||||
if (!x) return;
|
||||
(x: string); // ok
|
||||
yield * gen;
|
||||
(x: string); // ok
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
function* a(x: { a: void | string }): Generator<void, void, void> {
|
||||
if (!x.a) return;
|
||||
(x.a: string); // ok
|
||||
yield;
|
||||
(x.a: string); // error
|
||||
}
|
||||
|
||||
function* b(x: void | string): Generator<void, void, void> {
|
||||
if (!x) return;
|
||||
(x: string); // ok
|
||||
yield;
|
||||
(x: string); // ok
|
||||
}
|
||||
|
||||
declare function fn(): Generator<void, void, void>;
|
||||
|
||||
function* c(x: { a: void | string }): Generator<void, void, void> {
|
||||
const gen = fn();
|
||||
if (!x.a) return;
|
||||
(x.a: string); // ok
|
||||
yield* gen;
|
||||
(x.a: string); // error
|
||||
}
|
||||
|
||||
function* d(x: void | string): Generator<void, void, void> {
|
||||
const gen = fn();
|
||||
if (!x) return;
|
||||
(x: string); // ok
|
||||
yield* gen;
|
||||
(x: string); // ok
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`return.js 1`] = `
|
||||
"function test1(gen: Generator<void, string, void>) {
|
||||
// You can pass whatever you like to return, it doesn't need to be related to
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
function *a(x: {a: void | string}): Generator<void, void, void> {
|
||||
if (!x.a) return;
|
||||
(x.a: string); // ok
|
||||
yield;
|
||||
(x.a: string); // error
|
||||
}
|
||||
|
||||
function *b(x: void | string): Generator<void, void, void> {
|
||||
if (!x) return;
|
||||
(x: string); // ok
|
||||
yield;
|
||||
(x: string); // ok
|
||||
}
|
||||
|
||||
declare function fn(): Generator<void, void, void>;
|
||||
|
||||
function *c(x: {a: void | string}): Generator<void, void, void> {
|
||||
const gen = fn();
|
||||
if (!x.a) return;
|
||||
(x.a: string); // ok
|
||||
yield * gen;
|
||||
(x.a: string); // error
|
||||
}
|
||||
|
||||
function *d(x: void | string): Generator<void, void, void> {
|
||||
const gen = fn();
|
||||
if (!x) return;
|
||||
(x: string); // ok
|
||||
yield * gen;
|
||||
(x: string); // ok
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname);
|
|
@ -7,9 +7,31 @@ exports[`getters_and_setters.js 1`] = `
|
|||
|
||||
var f = {
|
||||
get a() { return 4; },
|
||||
set b(x: number) { this.c = b; },
|
||||
set b(x: number) { this.c = x; },
|
||||
c: 10,
|
||||
get ['d']() { return 'foo'; },
|
||||
set ['d'](x: number) {},
|
||||
};
|
||||
|
||||
type T = {
|
||||
get a(): number,
|
||||
set b(x: number): void,
|
||||
c: 10,
|
||||
}
|
||||
|
||||
declare class Foo {
|
||||
get a(): number;
|
||||
set b(x: number): void;
|
||||
c: 10;
|
||||
}
|
||||
|
||||
class Bar {
|
||||
get a() { return 4; }
|
||||
set b(x: number) { this.c = x; }
|
||||
c: number;
|
||||
get ['d']() { return 'foo'; }
|
||||
set ['d'](x: number) {}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/**
|
||||
* @flow
|
||||
|
@ -20,9 +42,39 @@ var f = {
|
|||
return 4;
|
||||
},
|
||||
set b(x: number) {
|
||||
this.c = b;
|
||||
this.c = x;
|
||||
},
|
||||
c: 10,
|
||||
get [\\"d\\"]() {
|
||||
return \\"foo\\";
|
||||
},
|
||||
set [\\"d\\"](x: number) {}
|
||||
};
|
||||
|
||||
type T = {
|
||||
a: () => number,
|
||||
b: (x: number) => void,
|
||||
c: 10
|
||||
};
|
||||
|
||||
declare class Foo {
|
||||
a: () => number,
|
||||
b: (x: number) => void,
|
||||
c: 10
|
||||
}
|
||||
|
||||
class Bar {
|
||||
get a() {
|
||||
return 4;
|
||||
}
|
||||
set b(x: number) {
|
||||
this.c = x;
|
||||
}
|
||||
c: number;
|
||||
get [\\"d\\"]() {
|
||||
return \\"foo\\";
|
||||
}
|
||||
set [\\"d\\"](x: number) {}
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
|
|
@ -4,6 +4,28 @@
|
|||
|
||||
var f = {
|
||||
get a() { return 4; },
|
||||
set b(x: number) { this.c = b; },
|
||||
set b(x: number) { this.c = x; },
|
||||
c: 10,
|
||||
get ['d']() { return 'foo'; },
|
||||
set ['d'](x: number) {},
|
||||
};
|
||||
|
||||
type T = {
|
||||
get a(): number,
|
||||
set b(x: number): void,
|
||||
c: 10,
|
||||
}
|
||||
|
||||
declare class Foo {
|
||||
get a(): number;
|
||||
set b(x: number): void;
|
||||
c: 10;
|
||||
}
|
||||
|
||||
class Bar {
|
||||
get a() { return 4; }
|
||||
set b(x: number) { this.c = x; }
|
||||
c: number;
|
||||
get ['d']() { return 'foo'; }
|
||||
set ['d'](x: number) {}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ class Foo {
|
|||
|
||||
propOverriddenWithSetter: number;
|
||||
set propOverriddenWithSetter(x: string) { }
|
||||
|
||||
set [z](x: string) {}
|
||||
get [z](): string { return string; }
|
||||
};
|
||||
|
||||
var foo = new Foo();
|
||||
|
@ -107,6 +110,11 @@ class Foo {
|
|||
|
||||
propOverriddenWithSetter: number;
|
||||
set propOverriddenWithSetter(x: string) {}
|
||||
|
||||
set [z](x: string) {}
|
||||
get [z](): string {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
var foo = new Foo();
|
||||
|
@ -133,6 +141,105 @@ foo.propOverriddenWithSetter = 123; // Error number ~> string
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`declare_class.js 1`] = `
|
||||
"/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var z: number = 123;
|
||||
|
||||
declare class Foo {
|
||||
get goodGetterWithAnnotation(): number;
|
||||
set goodSetterWithAnnotation(x: number): void;
|
||||
|
||||
get propWithMatchingGetterAndSetter(): number;
|
||||
set propWithMatchingGetterAndSetter(x: number): void;
|
||||
|
||||
// The getter and setter need not have the same type - no error
|
||||
get propWithSubtypingGetterAndSetter(): ?number;
|
||||
set propWithSubtypingGetterAndSetter(x: number): void;
|
||||
|
||||
// The getter and setter need not have the same type - no error
|
||||
set propWithSubtypingGetterAndSetterReordered(x: number): void;
|
||||
get propWithSubtypingGetterAndSetterReordered(): ?number;
|
||||
|
||||
get propWithMismatchingGetterAndSetter(): number;
|
||||
set propWithMismatchingGetterAndSetter(x: string): void; // doesn't match getter (OK)
|
||||
|
||||
propOverriddenWithGetter: number;
|
||||
get propOverriddenWithGetter(): string;
|
||||
|
||||
propOverriddenWithSetter: number;
|
||||
set propOverriddenWithSetter(x: string): void;
|
||||
};
|
||||
|
||||
var foo = new Foo();
|
||||
|
||||
// Test getting properties with getters
|
||||
var testGetterNoError2: number = foo.goodGetterWithAnnotation;
|
||||
|
||||
var testGetterWithError2: string = foo.goodGetterWithAnnotation; // Error number ~> string
|
||||
|
||||
// Test setting properties with getters
|
||||
foo.goodSetterWithAnnotation = 123;
|
||||
|
||||
foo.goodSetterWithAnnotation = \\"hello\\"; // Error string ~> number
|
||||
|
||||
var testSubtypingGetterAndSetter: number = foo.propWithSubtypingGetterAndSetter; // Error ?number ~> number
|
||||
|
||||
var testPropOverridenWithGetter: number = foo.propOverriddenWithGetter; // Error string ~> number
|
||||
foo.propOverriddenWithSetter = 123; // Error number ~> string
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var z: number = 123;
|
||||
|
||||
declare class Foo {
|
||||
goodGetterWithAnnotation: () => number,
|
||||
goodSetterWithAnnotation: (x: number) => void,
|
||||
|
||||
propWithMatchingGetterAndSetter: () => number,
|
||||
propWithMatchingGetterAndSetter: (x: number) => void,
|
||||
|
||||
// The getter and setter need not have the same type - no error
|
||||
propWithSubtypingGetterAndSetter: () => ?number,
|
||||
propWithSubtypingGetterAndSetter: (x: number) => void,
|
||||
|
||||
// The getter and setter need not have the same type - no error
|
||||
propWithSubtypingGetterAndSetterReordered: (x: number) => void,
|
||||
propWithSubtypingGetterAndSetterReordered: () => ?number,
|
||||
|
||||
propWithMismatchingGetterAndSetter: () => number,
|
||||
propWithMismatchingGetterAndSetter: (x: string) => void, // doesn't match getter (OK)
|
||||
|
||||
propOverriddenWithGetter: number,
|
||||
propOverriddenWithGetter: () => string,
|
||||
|
||||
propOverriddenWithSetter: number,
|
||||
propOverriddenWithSetter: (x: string) => void
|
||||
}
|
||||
|
||||
var foo = new Foo();
|
||||
|
||||
// Test getting properties with getters
|
||||
var testGetterNoError2: number = foo.goodGetterWithAnnotation;
|
||||
|
||||
var testGetterWithError2: string = foo.goodGetterWithAnnotation; // Error number ~> string
|
||||
|
||||
// Test setting properties with getters
|
||||
foo.goodSetterWithAnnotation = 123;
|
||||
|
||||
foo.goodSetterWithAnnotation = \\"hello\\"; // Error string ~> number
|
||||
|
||||
var testSubtypingGetterAndSetter: number = foo.propWithSubtypingGetterAndSetter; // Error ?number ~> number
|
||||
|
||||
var testPropOverridenWithGetter: number = foo.propOverriddenWithGetter; // Error string ~> number
|
||||
foo.propOverriddenWithSetter = 123; // Error number ~> string
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`object.js 1`] = `
|
||||
"/**
|
||||
* @flow
|
||||
|
@ -166,6 +273,9 @@ var obj = {
|
|||
|
||||
set exampleOfOrderOfGetterAndSetterReordered(x: B) {},
|
||||
get exampleOfOrderOfGetterAndSetterReordered(): A { return new A(); },
|
||||
|
||||
set [z](x: string) {},
|
||||
get [z](): string { return string; },
|
||||
};
|
||||
|
||||
|
||||
|
@ -244,6 +354,11 @@ var obj = {
|
|||
set exampleOfOrderOfGetterAndSetterReordered(x: B) {},
|
||||
get exampleOfOrderOfGetterAndSetterReordered(): A {
|
||||
return new A();
|
||||
},
|
||||
|
||||
set [z](x: string) {},
|
||||
get [z](): string {
|
||||
return string;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -273,34 +388,153 @@ var testExampleOrOrderOfGetterAndSetterReordered: number = obj.exampleOfOrderOfG
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`react.js 1`] = `
|
||||
exports[`object_type.js 1`] = `
|
||||
"/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
React.createClass({
|
||||
propTypes: {
|
||||
get a() { return 4; },
|
||||
set b(x: number) { this.c = x; },
|
||||
c: 10,
|
||||
}
|
||||
});
|
||||
var z: number = 123;
|
||||
|
||||
class A {}
|
||||
class B extends A {}
|
||||
class C extends A {}
|
||||
|
||||
type T = {
|
||||
get goodGetterWithAnnotation(): number,
|
||||
set goodSetterWithAnnotation(x: number): void,
|
||||
|
||||
get propWithMatchingGetterAndSetter(): number,
|
||||
set propWithMatchingGetterAndSetter(x: number): void,
|
||||
|
||||
// The getter and setter need not have the same type
|
||||
get propWithSubtypingGetterAndSetter(): ?number, // OK
|
||||
set propWithSubtypingGetterAndSetter(x: number): void,
|
||||
|
||||
set propWithSubtypingGetterAndSetterReordered(x: number): void, // OK
|
||||
get propWithSubtypingGetterAndSetterReordered(): ?number,
|
||||
|
||||
get exampleOfOrderOfGetterAndSetter(): A,
|
||||
set exampleOfOrderOfGetterAndSetter(x: B): void,
|
||||
|
||||
set exampleOfOrderOfGetterAndSetterReordered(x: B): void,
|
||||
get exampleOfOrderOfGetterAndSetterReordered(): A,
|
||||
};
|
||||
|
||||
function test(obj: T) {
|
||||
// Test getting properties with getters
|
||||
var testGetterNoError2: number = obj.goodGetterWithAnnotation;
|
||||
|
||||
var testGetterWithError2: string = obj.goodGetterWithAnnotation; // Error number ~> string
|
||||
|
||||
// Test setting properties with getters
|
||||
obj.goodSetterWithAnnotation = 123;
|
||||
|
||||
obj.goodSetterWithAnnotation = \\"hello\\"; // Error string ~> number
|
||||
|
||||
var testSubtypingGetterAndSetter: number = obj.propWithSubtypingGetterAndSetter; // Error ?number ~> number
|
||||
|
||||
// When building this feature, it was tempting to flow the setter into the
|
||||
// getter and then use either the getter or setter as the type of the
|
||||
// property. This example shows the danger of using the getter's type
|
||||
obj.exampleOfOrderOfGetterAndSetter = new C(); // Error C ~> B
|
||||
|
||||
// And this example shows the danger of using the setter's type.
|
||||
var testExampleOrOrderOfGetterAndSetterReordered: number =
|
||||
obj.exampleOfOrderOfGetterAndSetterReordered; // Error A ~> B
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
React.createClass({
|
||||
var z: number = 123;
|
||||
|
||||
class A {}
|
||||
class B extends A {}
|
||||
class C extends A {}
|
||||
|
||||
type T = {
|
||||
goodGetterWithAnnotation: () => number,
|
||||
goodSetterWithAnnotation: (x: number) => void,
|
||||
propWithMatchingGetterAndSetter: () => number,
|
||||
propWithMatchingGetterAndSetter: (x: number) => void,
|
||||
// The getter and setter need not have the same type
|
||||
propWithSubtypingGetterAndSetter: () => ?number, // OK
|
||||
propWithSubtypingGetterAndSetter: (x: number) => void,
|
||||
propWithSubtypingGetterAndSetterReordered: (x: number) => void, // OK
|
||||
propWithSubtypingGetterAndSetterReordered: () => ?number,
|
||||
exampleOfOrderOfGetterAndSetter: () => A,
|
||||
exampleOfOrderOfGetterAndSetter: (x: B) => void,
|
||||
exampleOfOrderOfGetterAndSetterReordered: (x: B) => void,
|
||||
exampleOfOrderOfGetterAndSetterReordered: () => A
|
||||
};
|
||||
|
||||
function test(obj: T) {
|
||||
// Test getting properties with getters
|
||||
var testGetterNoError2: number = obj.goodGetterWithAnnotation;
|
||||
|
||||
var testGetterWithError2: string = obj.goodGetterWithAnnotation; // Error number ~> string
|
||||
|
||||
// Test setting properties with getters
|
||||
obj.goodSetterWithAnnotation = 123;
|
||||
|
||||
obj.goodSetterWithAnnotation = \\"hello\\"; // Error string ~> number
|
||||
|
||||
var testSubtypingGetterAndSetter: number = obj.propWithSubtypingGetterAndSetter; // Error ?number ~> number
|
||||
|
||||
// When building this feature, it was tempting to flow the setter into the
|
||||
// getter and then use either the getter or setter as the type of the
|
||||
// property. This example shows the danger of using the getter's type
|
||||
obj.exampleOfOrderOfGetterAndSetter = new C(); // Error C ~> B
|
||||
|
||||
// And this example shows the danger of using the setter's type.
|
||||
var testExampleOrOrderOfGetterAndSetterReordered: number = obj.exampleOfOrderOfGetterAndSetterReordered; // Error A ~> B
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`react.js 1`] = `
|
||||
"/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from \\"react\\";
|
||||
|
||||
const Example = React.createClass({
|
||||
propTypes: {
|
||||
get a() { return React.PropTypes.number.isRequired; },
|
||||
set b(x: number) { this.c = x; },
|
||||
c: React.PropTypes.string,
|
||||
}
|
||||
});
|
||||
|
||||
(<Example />); // error: property \`a\` not found
|
||||
(<Example a={0} />); // ok
|
||||
(<Example a=\\"bad\\" />); // error: number ~> string
|
||||
(<Example a={0} c={0} />); // error: number ~> string
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from \\"react\\";
|
||||
|
||||
const Example = React.createClass({
|
||||
propTypes: {
|
||||
get a() {
|
||||
return 4;
|
||||
return React.PropTypes.number.isRequired;
|
||||
},
|
||||
set b(x: number) {
|
||||
this.c = x;
|
||||
},
|
||||
c: 10
|
||||
c: React.PropTypes.string
|
||||
}
|
||||
});
|
||||
|
||||
<Example />; // error: property \`a\` not found
|
||||
<Example a={0} />; // ok
|
||||
<Example a=\\"bad\\" />; // error: number ~> string
|
||||
<Example a={0} c={0} />; // error: number ~> string
|
||||
"
|
||||
`;
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@ class Foo {
|
|||
|
||||
propOverriddenWithSetter: number;
|
||||
set propOverriddenWithSetter(x: string) { }
|
||||
|
||||
set [z](x: string) {}
|
||||
get [z](): string { return string; }
|
||||
};
|
||||
|
||||
var foo = new Foo();
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var z: number = 123;
|
||||
|
||||
declare class Foo {
|
||||
get goodGetterWithAnnotation(): number;
|
||||
set goodSetterWithAnnotation(x: number): void;
|
||||
|
||||
get propWithMatchingGetterAndSetter(): number;
|
||||
set propWithMatchingGetterAndSetter(x: number): void;
|
||||
|
||||
// The getter and setter need not have the same type - no error
|
||||
get propWithSubtypingGetterAndSetter(): ?number;
|
||||
set propWithSubtypingGetterAndSetter(x: number): void;
|
||||
|
||||
// The getter and setter need not have the same type - no error
|
||||
set propWithSubtypingGetterAndSetterReordered(x: number): void;
|
||||
get propWithSubtypingGetterAndSetterReordered(): ?number;
|
||||
|
||||
get propWithMismatchingGetterAndSetter(): number;
|
||||
set propWithMismatchingGetterAndSetter(x: string): void; // doesn't match getter (OK)
|
||||
|
||||
propOverriddenWithGetter: number;
|
||||
get propOverriddenWithGetter(): string;
|
||||
|
||||
propOverriddenWithSetter: number;
|
||||
set propOverriddenWithSetter(x: string): void;
|
||||
};
|
||||
|
||||
var foo = new Foo();
|
||||
|
||||
// Test getting properties with getters
|
||||
var testGetterNoError2: number = foo.goodGetterWithAnnotation;
|
||||
|
||||
var testGetterWithError2: string = foo.goodGetterWithAnnotation; // Error number ~> string
|
||||
|
||||
// Test setting properties with getters
|
||||
foo.goodSetterWithAnnotation = 123;
|
||||
|
||||
foo.goodSetterWithAnnotation = "hello"; // Error string ~> number
|
||||
|
||||
var testSubtypingGetterAndSetter: number = foo.propWithSubtypingGetterAndSetter; // Error ?number ~> number
|
||||
|
||||
var testPropOverridenWithGetter: number = foo.propOverriddenWithGetter; // Error string ~> number
|
||||
foo.propOverriddenWithSetter = 123; // Error number ~> string
|
|
@ -1 +1,5 @@
|
|||
run_spec(__dirname, null, ["babylon"]);
|
||||
run_spec(__dirname);
|
||||
|
||||
// TODO: These tests used to be run in babylon as well, but currently babylon
|
||||
// fails to parse them.
|
||||
// run_spec(__dirname, null, ["babylon"]);
|
||||
|
|
|
@ -30,6 +30,9 @@ var obj = {
|
|||
|
||||
set exampleOfOrderOfGetterAndSetterReordered(x: B) {},
|
||||
get exampleOfOrderOfGetterAndSetterReordered(): A { return new A(); },
|
||||
|
||||
set [z](x: string) {},
|
||||
get [z](): string { return string; },
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var z: number = 123;
|
||||
|
||||
class A {}
|
||||
class B extends A {}
|
||||
class C extends A {}
|
||||
|
||||
type T = {
|
||||
get goodGetterWithAnnotation(): number,
|
||||
set goodSetterWithAnnotation(x: number): void,
|
||||
|
||||
get propWithMatchingGetterAndSetter(): number,
|
||||
set propWithMatchingGetterAndSetter(x: number): void,
|
||||
|
||||
// The getter and setter need not have the same type
|
||||
get propWithSubtypingGetterAndSetter(): ?number, // OK
|
||||
set propWithSubtypingGetterAndSetter(x: number): void,
|
||||
|
||||
set propWithSubtypingGetterAndSetterReordered(x: number): void, // OK
|
||||
get propWithSubtypingGetterAndSetterReordered(): ?number,
|
||||
|
||||
get exampleOfOrderOfGetterAndSetter(): A,
|
||||
set exampleOfOrderOfGetterAndSetter(x: B): void,
|
||||
|
||||
set exampleOfOrderOfGetterAndSetterReordered(x: B): void,
|
||||
get exampleOfOrderOfGetterAndSetterReordered(): A,
|
||||
};
|
||||
|
||||
function test(obj: T) {
|
||||
// Test getting properties with getters
|
||||
var testGetterNoError2: number = obj.goodGetterWithAnnotation;
|
||||
|
||||
var testGetterWithError2: string = obj.goodGetterWithAnnotation; // Error number ~> string
|
||||
|
||||
// Test setting properties with getters
|
||||
obj.goodSetterWithAnnotation = 123;
|
||||
|
||||
obj.goodSetterWithAnnotation = "hello"; // Error string ~> number
|
||||
|
||||
var testSubtypingGetterAndSetter: number = obj.propWithSubtypingGetterAndSetter; // Error ?number ~> number
|
||||
|
||||
// When building this feature, it was tempting to flow the setter into the
|
||||
// getter and then use either the getter or setter as the type of the
|
||||
// property. This example shows the danger of using the getter's type
|
||||
obj.exampleOfOrderOfGetterAndSetter = new C(); // Error C ~> B
|
||||
|
||||
// And this example shows the danger of using the setter's type.
|
||||
var testExampleOrOrderOfGetterAndSetterReordered: number =
|
||||
obj.exampleOfOrderOfGetterAndSetterReordered; // Error A ~> B
|
||||
}
|
|
@ -2,10 +2,17 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
React.createClass({
|
||||
import React from "react";
|
||||
|
||||
const Example = React.createClass({
|
||||
propTypes: {
|
||||
get a() { return 4; },
|
||||
get a() { return React.PropTypes.number.isRequired; },
|
||||
set b(x: number) { this.c = x; },
|
||||
c: 10,
|
||||
c: React.PropTypes.string,
|
||||
}
|
||||
});
|
||||
|
||||
(<Example />); // error: property `a` not found
|
||||
(<Example a={0} />); // ok
|
||||
(<Example a="bad" />); // error: number ~> string
|
||||
(<Example a={0} c={0} />); // error: number ~> string
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
/* @flow */
|
||||
|
||||
var test = require('test');
|
||||
|
||||
(test: boolean);
|
||||
|
||||
module.exports = test;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue