From b94924533690661c9b5e6b2ef60b136e624adb83 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 11 Oct 2017 15:13:33 -0700 Subject: [PATCH] Add ValueModule as a valid object literal type, as they are immutable (#19090) * Add ValueModule as a valid object literal type, as they are immutable * Rename method based on usage --- src/compiler/checker.ts | 10 +++---- .../inferredIndexerOnNamespaceImport.js | 28 +++++++++++++++++++ .../inferredIndexerOnNamespaceImport.symbols | 23 +++++++++++++++ .../inferredIndexerOnNamespaceImport.types | 26 +++++++++++++++++ .../inferredIndexerOnNamespaceImport.ts | 12 ++++++++ 5 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/inferredIndexerOnNamespaceImport.js create mode 100644 tests/baselines/reference/inferredIndexerOnNamespaceImport.symbols create mode 100644 tests/baselines/reference/inferredIndexerOnNamespaceImport.types create mode 100644 tests/cases/compiler/inferredIndexerOnNamespaceImport.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 36ee2a00eb9..a756faae036 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6274,7 +6274,7 @@ namespace ts { } function getImplicitIndexTypeOfType(type: Type, kind: IndexKind): Type { - if (isObjectLiteralType(type)) { + if (isObjectTypeWithInferableIndex(type)) { const propTypes: Type[] = []; for (const prop of getPropertiesOfType(type)) { if (kind === IndexKind.String || isNumericLiteralName(prop.escapedName)) { @@ -9831,7 +9831,7 @@ namespace ts { // if T is related to U. return kind === IndexKind.String && isRelatedTo(getTemplateTypeFromMappedType(source), targetInfo.type, reportErrors); } - if (isObjectLiteralType(source)) { + if (isObjectTypeWithInferableIndex(source)) { let related = Ternary.True; if (kind === IndexKind.String) { const sourceNumberInfo = getIndexInfoOfType(source, IndexKind.Number); @@ -10344,11 +10344,11 @@ namespace ts { } /** - * Return true if type was inferred from an object literal or written as an object type literal + * Return true if type was inferred from an object literal, written as an object type literal, or is the shape of a module * with no call or construct signatures. */ - function isObjectLiteralType(type: Type) { - return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral)) !== 0 && + function isObjectTypeWithInferableIndex(type: Type) { + return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.ValueModule)) !== 0 && getSignaturesOfType(type, SignatureKind.Call).length === 0 && getSignaturesOfType(type, SignatureKind.Construct).length === 0; } diff --git a/tests/baselines/reference/inferredIndexerOnNamespaceImport.js b/tests/baselines/reference/inferredIndexerOnNamespaceImport.js new file mode 100644 index 00000000000..10fbc0890b7 --- /dev/null +++ b/tests/baselines/reference/inferredIndexerOnNamespaceImport.js @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/inferredIndexerOnNamespaceImport.ts] //// + +//// [foo.ts] +export const x = 3; +export const y = 5; + +//// [bar.ts] +import * as foo from "./foo"; + +function f(map: { [k: string]: number }) { + // ... +} + +f(foo); + +//// [foo.js] +"use strict"; +exports.__esModule = true; +exports.x = 3; +exports.y = 5; +//// [bar.js] +"use strict"; +exports.__esModule = true; +var foo = require("./foo"); +function f(map) { + // ... +} +f(foo); diff --git a/tests/baselines/reference/inferredIndexerOnNamespaceImport.symbols b/tests/baselines/reference/inferredIndexerOnNamespaceImport.symbols new file mode 100644 index 00000000000..ea0337ee9c2 --- /dev/null +++ b/tests/baselines/reference/inferredIndexerOnNamespaceImport.symbols @@ -0,0 +1,23 @@ +=== tests/cases/compiler/foo.ts === +export const x = 3; +>x : Symbol(x, Decl(foo.ts, 0, 12)) + +export const y = 5; +>y : Symbol(y, Decl(foo.ts, 1, 12)) + +=== tests/cases/compiler/bar.ts === +import * as foo from "./foo"; +>foo : Symbol(foo, Decl(bar.ts, 0, 6)) + +function f(map: { [k: string]: number }) { +>f : Symbol(f, Decl(bar.ts, 0, 29)) +>map : Symbol(map, Decl(bar.ts, 2, 11)) +>k : Symbol(k, Decl(bar.ts, 2, 19)) + + // ... +} + +f(foo); +>f : Symbol(f, Decl(bar.ts, 0, 29)) +>foo : Symbol(foo, Decl(bar.ts, 0, 6)) + diff --git a/tests/baselines/reference/inferredIndexerOnNamespaceImport.types b/tests/baselines/reference/inferredIndexerOnNamespaceImport.types new file mode 100644 index 00000000000..4a88b2330a0 --- /dev/null +++ b/tests/baselines/reference/inferredIndexerOnNamespaceImport.types @@ -0,0 +1,26 @@ +=== tests/cases/compiler/foo.ts === +export const x = 3; +>x : 3 +>3 : 3 + +export const y = 5; +>y : 5 +>5 : 5 + +=== tests/cases/compiler/bar.ts === +import * as foo from "./foo"; +>foo : typeof foo + +function f(map: { [k: string]: number }) { +>f : (map: { [k: string]: number; }) => void +>map : { [k: string]: number; } +>k : string + + // ... +} + +f(foo); +>f(foo) : void +>f : (map: { [k: string]: number; }) => void +>foo : typeof foo + diff --git a/tests/cases/compiler/inferredIndexerOnNamespaceImport.ts b/tests/cases/compiler/inferredIndexerOnNamespaceImport.ts new file mode 100644 index 00000000000..dd231361d27 --- /dev/null +++ b/tests/cases/compiler/inferredIndexerOnNamespaceImport.ts @@ -0,0 +1,12 @@ +// @filename: foo.ts +export const x = 3; +export const y = 5; + +// @filename: bar.ts +import * as foo from "./foo"; + +function f(map: { [k: string]: number }) { + // ... +} + +f(foo); \ No newline at end of file