Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27767,6 +27767,27 @@ namespace ts {
hasModifier(parameter, ModifierFlags.ParameterPropertyModifier);
}

function isJSContainerFunctionDeclaration(node: Declaration): boolean {
const declaration = getParseTreeNode(node, isFunctionDeclaration);
if (!declaration) {
return false;
}
const symbol = getSymbolOfNode(declaration);
if (!symbol || !(symbol.flags & SymbolFlags.Function)) {
return false;
}
return !!forEachEntry(getExportsOfSymbol(symbol), p => isPropertyAccessExpression(p.valueDeclaration));
}

function getPropertiesOfContainerFunction(node: Declaration): Symbol[] {
const declaration = getParseTreeNode(node, isFunctionDeclaration);
if (!declaration) {
return emptyArray;
}
const symbol = getSymbolOfNode(declaration);
return symbol && getPropertiesOfType(getTypeOfSymbol(symbol)) || emptyArray;
}

function getNodeCheckFlags(node: Node): NodeCheckFlags {
return getNodeLinks(node).flags || 0;
}
Expand Down Expand Up @@ -27874,7 +27895,7 @@ namespace ts {
}
}

function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) {
function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) {
const declaration = getParseTreeNode(declarationIn, isVariableLikeOrAccessor);
if (!declaration) {
return createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode;
Expand Down Expand Up @@ -28007,6 +28028,8 @@ namespace ts {
isImplementationOfOverload,
isRequiredInitializedParameter,
isOptionalUninitializedParameterProperty,
isJSContainerFunctionDeclaration,
getPropertiesOfContainerFunction,
createTypeOfDeclaration,
createReturnTypeOfSignatureDeclaration,
createTypeOfExpression,
Expand Down
17 changes: 16 additions & 1 deletion src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ namespace ts {
}
case SyntaxKind.FunctionDeclaration: {
// Generators lose their generator-ness, excepting their return type
return cleanup(updateFunctionDeclaration(
const clean = cleanup(updateFunctionDeclaration(
input,
/*decorators*/ undefined,
ensureModifiers(input, isPrivate),
Expand All @@ -982,6 +982,21 @@ namespace ts {
ensureType(input, input.type),
/*body*/ undefined
));
if (clean && resolver.isJSContainerFunctionDeclaration(input)) {
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
if (!isPropertyAccessExpression(p.valueDeclaration)) {
return undefined;
}
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined);
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl]));
});
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input, isPrivate), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);
return [clean, namespaceDecl];
}
else {
return clean;
}
}
case SyntaxKind.ModuleDeclaration: {
needsDeclare = false;
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3374,7 +3374,9 @@ namespace ts {
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
isJSContainerFunctionDeclaration(node: FunctionDeclaration): boolean;
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): Expression;
Expand Down
58 changes: 44 additions & 14 deletions tests/baselines/reference/typeFromPropertyAssignment29.errors.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(30,14): error TS2339: Property 'prop' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(31,14): error TS2339: Property 'm' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(34,22): error TS2339: Property 'prop' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(34,42): error TS2339: Property 'm' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(40,14): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(41,14): error TS2339: Property 'm' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(44,22): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(44,42): error TS2339: Property 'm' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(50,14): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoExpr3'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(51,14): error TS2339: Property 'm' does not exist on type 'typeof ExpandoExpr3'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(54,22): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoExpr3'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(54,42): error TS2339: Property 'm' does not exist on type 'typeof ExpandoExpr3'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(60,14): error TS2339: Property 'prop' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(61,14): error TS2339: Property 'm' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(64,22): error TS2339: Property 'prop' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(64,42): error TS2339: Property 'm' does not exist on type '(n: number) => string'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(70,14): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(71,14): error TS2339: Property 'm' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(74,22): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(74,42): error TS2339: Property 'm' does not exist on type 'typeof ExpandoClass'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(80,14): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoExpr3'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(81,14): error TS2339: Property 'm' does not exist on type 'typeof ExpandoExpr3'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(84,22): error TS2339: Property 'prop' does not exist on type 'typeof ExpandoExpr3'.
tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(84,42): error TS2339: Property 'm' does not exist on type 'typeof ExpandoExpr3'.


==== tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts (12 errors) ====
Expand All @@ -25,11 +25,12 @@ tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(54,42): error TS23
const ExpandoExpr = function (n: number) {
return n.toString();
}
ExpandoExpr.prop = 2
ExpandoExpr.prop = { x: 2 }
ExpandoExpr.prop = { y: "" }
ExpandoExpr.m = function(n: number) {
return n + 1;
}
var n = ExpandoExpr.prop + ExpandoExpr.m(12) + ExpandoExpr(101).length
var n = (ExpandoExpr.prop.x || 0) + ExpandoExpr.m(12) + ExpandoExpr(101).length

const ExpandoArrow = (n: number) => n.toString();
ExpandoArrow.prop = 2
Expand All @@ -38,6 +39,35 @@ tests/cases/conformance/salsa/typeFromPropertyAssignment29.ts(54,42): error TS23

}

function ExpandoNested(n: number) {
const nested = function (m: number) {
return n + m;
};
nested.total = n + 1_000_000;
return nested;
}
ExpandoNested.also = -1;

function ExpandoMerge(n: number) {
return n * 100;
}
ExpandoMerge.p1 = 111
namespace ExpandoMerge {
export var p2 = 222;
}
namespace ExpandoMerge {
export var p3 = 333;
}
var n = ExpandoMerge.p1 + ExpandoMerge.p2 + ExpandoMerge.p3 + ExpandoMerge(1);

namespace Ns {
function ExpandoNamespace(): void {}
ExpandoNamespace.p6 = 42;
export function foo() {
return ExpandoNamespace;
}
}

// Should not work in Typescript -- must be const
var ExpandoExpr2 = function (n: number) {
return n.toString();
Expand Down
130 changes: 126 additions & 4 deletions tests/baselines/reference/typeFromPropertyAssignment29.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ var n = ExpandoDecl.prop + ExpandoDecl.m(12) + ExpandoDecl(101).length
const ExpandoExpr = function (n: number) {
return n.toString();
}
ExpandoExpr.prop = 2
ExpandoExpr.prop = { x: 2 }
ExpandoExpr.prop = { y: "" }
ExpandoExpr.m = function(n: number) {
return n + 1;
}
var n = ExpandoExpr.prop + ExpandoExpr.m(12) + ExpandoExpr(101).length
var n = (ExpandoExpr.prop.x || 0) + ExpandoExpr.m(12) + ExpandoExpr(101).length

const ExpandoArrow = (n: number) => n.toString();
ExpandoArrow.prop = 2
Expand All @@ -24,6 +25,35 @@ ExpandoArrow.m = function(n: number) {

}

function ExpandoNested(n: number) {
const nested = function (m: number) {
return n + m;
};
nested.total = n + 1_000_000;
return nested;
}
ExpandoNested.also = -1;

function ExpandoMerge(n: number) {
return n * 100;
}
ExpandoMerge.p1 = 111
namespace ExpandoMerge {
export var p2 = 222;
}
namespace ExpandoMerge {
export var p3 = 333;
}
var n = ExpandoMerge.p1 + ExpandoMerge.p2 + ExpandoMerge.p3 + ExpandoMerge(1);

namespace Ns {
function ExpandoNamespace(): void {}
ExpandoNamespace.p6 = 42;
export function foo() {
return ExpandoNamespace;
}
}

// Should not work in Typescript -- must be const
var ExpandoExpr2 = function (n: number) {
return n.toString();
Expand Down Expand Up @@ -68,16 +98,45 @@ var n = ExpandoDecl.prop + ExpandoDecl.m(12) + ExpandoDecl(101).length;
var ExpandoExpr = function (n) {
return n.toString();
};
ExpandoExpr.prop = 2;
ExpandoExpr.prop = { x: 2 };
ExpandoExpr.prop = { y: "" };
ExpandoExpr.m = function (n) {
return n + 1;
};
var n = ExpandoExpr.prop + ExpandoExpr.m(12) + ExpandoExpr(101).length;
var n = (ExpandoExpr.prop.x || 0) + ExpandoExpr.m(12) + ExpandoExpr(101).length;
var ExpandoArrow = function (n) { return n.toString(); };
ExpandoArrow.prop = 2;
ExpandoArrow.m = function (n) {
return n + 1;
};
function ExpandoNested(n) {
var nested = function (m) {
return n + m;
};
nested.total = n + 1000000;
return nested;
}
ExpandoNested.also = -1;
function ExpandoMerge(n) {
return n * 100;
}
ExpandoMerge.p1 = 111;
(function (ExpandoMerge) {
ExpandoMerge.p2 = 222;
})(ExpandoMerge || (ExpandoMerge = {}));
(function (ExpandoMerge) {
ExpandoMerge.p3 = 333;
})(ExpandoMerge || (ExpandoMerge = {}));
var n = ExpandoMerge.p1 + ExpandoMerge.p2 + ExpandoMerge.p3 + ExpandoMerge(1);
var Ns;
(function (Ns) {
function ExpandoNamespace() { }
ExpandoNamespace.p6 = 42;
function foo() {
return ExpandoNamespace;
}
Ns.foo = foo;
})(Ns || (Ns = {}));
// Should not work in Typescript -- must be const
var ExpandoExpr2 = function (n) {
return n.toString();
Expand Down Expand Up @@ -111,3 +170,66 @@ ExpandoExpr3.m = function (n) {
return n + 1;
};
var n = ExpandoExpr3.prop + ExpandoExpr3.m(13) + new ExpandoExpr3().n;


//// [typeFromPropertyAssignment29.d.ts]
declare function ExpandoDecl(n: number): string;
declare namespace ExpandoDecl {
var prop: number;
var m: (n: number) => number;
}
declare var n: number;
declare const ExpandoExpr: {
(n: number): string;
prop: {
x: number;
y?: undefined;
} | {
y: string;
x?: undefined;
};
m(n: number): number;
};
declare var n: number;
declare const ExpandoArrow: {
(n: number): string;
prop: number;
m(n: number): number;
};
declare function ExpandoNested(n: number): {
(m: number): number;
total: number;
};
declare namespace ExpandoNested {
var also: number;
}
declare function ExpandoMerge(n: number): number;
declare namespace ExpandoMerge {
var p1: number;
}
declare namespace ExpandoMerge {
var p2: number;
}
declare namespace ExpandoMerge {
var p3: number;
}
declare var n: number;
declare namespace Ns {
function ExpandoNamespace(): void;
namespace ExpandoNamespace {
var p6: number;
}
function foo(): typeof ExpandoNamespace;
}
declare var ExpandoExpr2: (n: number) => string;
declare var n: number;
declare class ExpandoClass {
n: number;
}
declare var n: number;
declare var ExpandoExpr3: {
new (): {
n: number;
};
};
declare var n: number;
Loading