Merge pull request #14222 from Microsoft/addAnyStringIndexerToJSObjects

Add a string indexer to any for object literals on a .js file
This commit is contained in:
Mohamed Hegazy 2017-03-06 16:44:30 -08:00 committed by GitHub
commit b3161e365a
7 changed files with 313 additions and 8 deletions

View file

@ -244,6 +244,7 @@ namespace ts {
const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
const globals = createMap<Symbol>();
/**
@ -12252,6 +12253,7 @@ namespace ts {
const contextualType = getApparentTypeOfContextualType(node);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
const isJSObjectLiteral = !contextualType && isInJavaScriptFile(node);
let typeFlags: TypeFlags = 0;
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
@ -12389,8 +12391,8 @@ namespace ts {
return createObjectLiteralType();
function createObjectLiteralType() {
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
const stringIndexInfo = isJSObjectLiteral ? jsObjectLiteralIndexInfo : hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
const numberIndexInfo = hasComputedNumberProperty && !isJSObjectLiteral ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);

View file

@ -1,7 +1,7 @@
=== tests/cases/compiler/a.js ===
function foo() {
>foo : () => { a: number; b: string; }
>foo : () => { [x: string]: any; a: number; b: string; }
var a = 10;
>a : number
@ -12,7 +12,7 @@ function foo() {
>"Hello" : "Hello"
return {
>{ a, b } : { a: number; b: string; }
>{ a, b } : { [x: string]: any; a: number; b: string; }
a,
>a : number

View file

@ -0,0 +1,63 @@
//// [tests/cases/conformance/salsa/jsObjectsMarkedAsOpenEnded.ts] ////
//// [a.js]
var variable = {};
variable.a = 0;
class C {
initializedMember = {};
constructor() {
this.member = {};
this.member.a = 0;
}
}
var obj = {
property: {}
};
obj.property.a = 0;
var arr = [{}];
function getObj() {
return {};
}
//// [b.ts]
variable.a = 1;
(new C()).member.a = 1;
(new C()).initializedMember.a = 1;
obj.property.a = 1;
arr[0].a = 1;
getObj().a = 1;
//// [output.js]
var variable = {};
variable.a = 0;
var C = (function () {
function C() {
this.initializedMember = {};
this.member = {};
this.member.a = 0;
}
return C;
}());
var obj = {
property: {}
};
obj.property.a = 0;
var arr = [{}];
function getObj() {
return {};
}
variable.a = 1;
(new C()).member.a = 1;
(new C()).initializedMember.a = 1;
obj.property.a = 1;
arr[0].a = 1;
getObj().a = 1;

View file

@ -0,0 +1,76 @@
=== tests/cases/conformance/salsa/a.js ===
var variable = {};
>variable : Symbol(variable, Decl(a.js, 1, 3))
variable.a = 0;
>variable : Symbol(variable, Decl(a.js, 1, 3))
class C {
>C : Symbol(C, Decl(a.js, 2, 15))
initializedMember = {};
>initializedMember : Symbol(C.initializedMember, Decl(a.js, 4, 9))
constructor() {
this.member = {};
>this.member : Symbol(C.member, Decl(a.js, 6, 19))
>this : Symbol(C, Decl(a.js, 2, 15))
>member : Symbol(C.member, Decl(a.js, 6, 19))
this.member.a = 0;
>this.member : Symbol(C.member, Decl(a.js, 6, 19))
>this : Symbol(C, Decl(a.js, 2, 15))
>member : Symbol(C.member, Decl(a.js, 6, 19))
}
}
var obj = {
>obj : Symbol(obj, Decl(a.js, 12, 3))
property: {}
>property : Symbol(property, Decl(a.js, 12, 11))
};
obj.property.a = 0;
>obj.property : Symbol(property, Decl(a.js, 12, 11))
>obj : Symbol(obj, Decl(a.js, 12, 3))
>property : Symbol(property, Decl(a.js, 12, 11))
var arr = [{}];
>arr : Symbol(arr, Decl(a.js, 18, 3))
function getObj() {
>getObj : Symbol(getObj, Decl(a.js, 18, 15))
return {};
}
=== tests/cases/conformance/salsa/b.ts ===
variable.a = 1;
>variable : Symbol(variable, Decl(a.js, 1, 3))
(new C()).member.a = 1;
>(new C()).member : Symbol(C.member, Decl(a.js, 6, 19))
>C : Symbol(C, Decl(a.js, 2, 15))
>member : Symbol(C.member, Decl(a.js, 6, 19))
(new C()).initializedMember.a = 1;
>(new C()).initializedMember : Symbol(C.initializedMember, Decl(a.js, 4, 9))
>C : Symbol(C, Decl(a.js, 2, 15))
>initializedMember : Symbol(C.initializedMember, Decl(a.js, 4, 9))
obj.property.a = 1;
>obj.property : Symbol(property, Decl(a.js, 12, 11))
>obj : Symbol(obj, Decl(a.js, 12, 3))
>property : Symbol(property, Decl(a.js, 12, 11))
arr[0].a = 1;
>arr : Symbol(arr, Decl(a.js, 18, 3))
getObj().a = 1;
>getObj : Symbol(getObj, Decl(a.js, 18, 15))

View file

@ -0,0 +1,128 @@
=== tests/cases/conformance/salsa/a.js ===
var variable = {};
>variable : { [x: string]: any; }
>{} : { [x: string]: any; }
variable.a = 0;
>variable.a = 0 : 0
>variable.a : any
>variable : { [x: string]: any; }
>a : any
>0 : 0
class C {
>C : C
initializedMember = {};
>initializedMember : { [x: string]: any; }
>{} : { [x: string]: any; }
constructor() {
this.member = {};
>this.member = {} : { [x: string]: any; }
>this.member : { [x: string]: any; }
>this : this
>member : { [x: string]: any; }
>{} : { [x: string]: any; }
this.member.a = 0;
>this.member.a = 0 : 0
>this.member.a : any
>this.member : { [x: string]: any; }
>this : this
>member : { [x: string]: any; }
>a : any
>0 : 0
}
}
var obj = {
>obj : { [x: string]: any; property: { [x: string]: any; }; }
>{ property: {}} : { [x: string]: any; property: { [x: string]: any; }; }
property: {}
>property : { [x: string]: any; }
>{} : { [x: string]: any; }
};
obj.property.a = 0;
>obj.property.a = 0 : 0
>obj.property.a : any
>obj.property : { [x: string]: any; }
>obj : { [x: string]: any; property: { [x: string]: any; }; }
>property : { [x: string]: any; }
>a : any
>0 : 0
var arr = [{}];
>arr : { [x: string]: any; }[]
>[{}] : { [x: string]: any; }[]
>{} : { [x: string]: any; }
function getObj() {
>getObj : () => { [x: string]: any; }
return {};
>{} : { [x: string]: any; }
}
=== tests/cases/conformance/salsa/b.ts ===
variable.a = 1;
>variable.a = 1 : 1
>variable.a : any
>variable : { [x: string]: any; }
>a : any
>1 : 1
(new C()).member.a = 1;
>(new C()).member.a = 1 : 1
>(new C()).member.a : any
>(new C()).member : { [x: string]: any; }
>(new C()) : C
>new C() : C
>C : typeof C
>member : { [x: string]: any; }
>a : any
>1 : 1
(new C()).initializedMember.a = 1;
>(new C()).initializedMember.a = 1 : 1
>(new C()).initializedMember.a : any
>(new C()).initializedMember : { [x: string]: any; }
>(new C()) : C
>new C() : C
>C : typeof C
>initializedMember : { [x: string]: any; }
>a : any
>1 : 1
obj.property.a = 1;
>obj.property.a = 1 : 1
>obj.property.a : any
>obj.property : { [x: string]: any; }
>obj : { [x: string]: any; property: { [x: string]: any; }; }
>property : { [x: string]: any; }
>a : any
>1 : 1
arr[0].a = 1;
>arr[0].a = 1 : 1
>arr[0].a : any
>arr[0] : { [x: string]: any; }
>arr : { [x: string]: any; }[]
>0 : 0
>a : any
>1 : 1
getObj().a = 1;
>getObj().a = 1 : 1
>getObj().a : any
>getObj() : { [x: string]: any; }
>getObj : () => { [x: string]: any; }
>a : any
>1 : 1

View file

@ -1,22 +1,22 @@
=== /a.ts ===
import foo from "foo";
>foo : { bar(): number; }
>foo : { [x: string]: any; bar(): number; }
foo.bar();
>foo.bar() : number
>foo.bar : () => number
>foo : { bar(): number; }
>foo : { [x: string]: any; bar(): number; }
>bar : () => number
=== /node_modules/foo/index.js ===
// Same as untypedModuleImport.ts but with --allowJs, so the package will actually be typed.
exports.default = { bar() { return 0; } }
>exports.default = { bar() { return 0; } } : { bar(): number; }
>exports.default = { bar() { return 0; } } : { [x: string]: any; bar(): number; }
>exports.default : any
>exports : any
>default : any
>{ bar() { return 0; } } : { bar(): number; }
>{ bar() { return 0; } } : { [x: string]: any; bar(): number; }
>bar : () => number
>0 : 0

View file

@ -0,0 +1,36 @@
// @out: output.js
// @allowJs: true
// @filename: a.js
var variable = {};
variable.a = 0;
class C {
initializedMember = {};
constructor() {
this.member = {};
this.member.a = 0;
}
}
var obj = {
property: {}
};
obj.property.a = 0;
var arr = [{}];
function getObj() {
return {};
}
// @filename: b.ts
variable.a = 1;
(new C()).member.a = 1;
(new C()).initializedMember.a = 1;
obj.property.a = 1;
arr[0].a = 1;
getObj().a = 1;