// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`test.js 1`] = ` ====================================options===================================== parsers: ["flow"] printWidth: 80 | printWidth =====================================input====================================== var x: { } = { foo: 0 }; var y: { foo?: string } = x; // OK in TypeScript, not OK in Flow var z: string = y.foo || ""; var o = { }; y = o; // OK; we know that narrowing could not have happened o.foo = 0; // future widening is constrained function bar(config: { foo?: number }) {} bar({}); bar({foo: ""}); =====================================output===================================== var x: {} = { foo: 0 }; var y: { foo?: string } = x; // OK in TypeScript, not OK in Flow var z: string = y.foo || ""; var o = {}; y = o; // OK; we know that narrowing could not have happened o.foo = 0; // future widening is constrained function bar(config: { foo?: number }) {} bar({}); bar({ foo: "" }); ================================================================================ `; exports[`test2.js 1`] = ` ====================================options===================================== parsers: ["flow"] printWidth: 80 | printWidth =====================================input====================================== var a: { foo?: string } = {}; a.foo = undefined; // This is not an error a.foo = null; // But this is an error var b: { foo?: ?string } = {}; b.foo = undefined; // This is fine b.foo = null; // Also fine var c: { foo?: string } = { foo: undefined }; // This is not an error var d: { foo?: string } = { foo: null }; // But this is an error var e: { foo?: ?string } = { foo: undefined }; // This is fine var f: { foo?: ?string } = { foo: null }; // Also fine =====================================output===================================== var a: { foo?: string } = {}; a.foo = undefined; // This is not an error a.foo = null; // But this is an error var b: { foo?: ?string } = {}; b.foo = undefined; // This is fine b.foo = null; // Also fine var c: { foo?: string } = { foo: undefined }; // This is not an error var d: { foo?: string } = { foo: null }; // But this is an error var e: { foo?: ?string } = { foo: undefined }; // This is fine var f: { foo?: ?string } = { foo: null }; // Also fine ================================================================================ `; exports[`test3.js 1`] = ` ====================================options===================================== parsers: ["flow"] printWidth: 80 | printWidth =====================================input====================================== // @flow /* object literals are sealed. this is simply a heuristic decision: most of the time, the rule gives the 'right' errors. an exception is when a literal is used as an initializer for an lvalue whose type specifies optional properties missing from the literal, as below. the problem becomes visible when a property assignment is then used to (legitimately) extend the object with an optional property - the variable's specific (path- dependent) type has become that of the literal which. without adjustment, will reject the property addition. the solution in cases where a sealed object type (as from an object literal) flows to an object type with optional properties, is to have the sealed type acquire the optional properties. */ // x has optional property b. // (note that the initializer here does not play into // the problem, it's just a placeholder. initializers // do not narrow the types of annotated variables as do // subsequent assignments.) // var x: { a: number, b?: number } = { a: 0 }; // now assign an object literal lacking property b. // the literal's type is sealed and has only a at creation. // but it then flows, specific ~> general, to x's annotation // type. at that point, it acquires b as an optional property. // x = { a: 0 }; // ...which allows this assignment to take place. x.b = 1; // T7810506 class A { x: { a: number, b?: string }; foo() { // Something similar should happen here, but doesn't: the problem is // made explicit by adding generics (see test3_failure.js introduced by // D2747512). There is a race between writing b on the object literal // type and adding b as an optional property to it, since in general we // cannot guarantee that the flow from the object literal to the // annotation will be processed before the flow involving the // access. Here we lose the race and get an error on the write. this.x = { a: 123 }; this.x.b = 'hello'; } } =====================================output===================================== // @flow /* object literals are sealed. this is simply a heuristic decision: most of the time, the rule gives the 'right' errors. an exception is when a literal is used as an initializer for an lvalue whose type specifies optional properties missing from the literal, as below. the problem becomes visible when a property assignment is then used to (legitimately) extend the object with an optional property - the variable's specific (path- dependent) type has become that of the literal which. without adjustment, will reject the property addition. the solution in cases where a sealed object type (as from an object literal) flows to an object type with optional properties, is to have the sealed type acquire the optional properties. */ // x has optional property b. // (note that the initializer here does not play into // the problem, it's just a placeholder. initializers // do not narrow the types of annotated variables as do // subsequent assignments.) // var x: { a: number, b?: number } = { a: 0 }; // now assign an object literal lacking property b. // the literal's type is sealed and has only a at creation. // but it then flows, specific ~> general, to x's annotation // type. at that point, it acquires b as an optional property. // x = { a: 0 }; // ...which allows this assignment to take place. x.b = 1; // T7810506 class A { x: { a: number, b?: string }; foo() { // Something similar should happen here, but doesn't: the problem is // made explicit by adding generics (see test3_failure.js introduced by // D2747512). There is a race between writing b on the object literal // type and adding b as an optional property to it, since in general we // cannot guarantee that the flow from the object literal to the // annotation will be processed before the flow involving the // access. Here we lose the race and get an error on the write. this.x = { a: 123 }; this.x.b = "hello"; } } ================================================================================ `; exports[`test3_exact_annot.js 1`] = ` ====================================options===================================== parsers: ["flow"] printWidth: 80 | printWidth =====================================input====================================== /* The logic that allows ({}: {p?:T}), described in test3.js, should _not_ also fire for exact annotations. */ const a: {| a: number |} = { a: 1 }; const b: { a: number, b?: number } = a; // error: property \`b\` not found b.b = 0; // because subsequent writes would widen the exact object (a.b: number); // error: property \`b\` not found =====================================output===================================== /* The logic that allows ({}: {p?:T}), described in test3.js, should _not_ also fire for exact annotations. */ const a: {| a: number |} = { a: 1 }; const b: { a: number, b?: number } = a; // error: property \`b\` not found b.b = 0; // because subsequent writes would widen the exact object (a.b: number); // error: property \`b\` not found ================================================================================ `; exports[`test3_failure.js 1`] = ` ====================================options===================================== parsers: ["flow"] printWidth: 80 | printWidth =====================================input====================================== // generalization of failure in test3.js class A { o: O; foo() { this.o.x = { a: 123 }; this.o.x.b = 'hello'; // this is a spurious error (see test3.js for details) } } =====================================output===================================== // generalization of failure in test3.js class A { o: O; foo() { this.o.x = { a: 123 }; this.o.x.b = "hello"; // this is a spurious error (see test3.js for details) } } ================================================================================ `;