-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Declaration emit includes function properties #26499
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
It does this by printing the type as an object literal type: ```ts function f() { } f.p = 1 ``` Appears in a d.ts as ```ts declare var f: { (): void; p: number; } ``` It would also be possible to represent it as a namespace merge. I'm not sure which is better. ```ts declare function f(): void; declare namespace f { export var p: number; } ``` In order to avoid a private-name-used error (though I think it was actually *unused*), I also had to change the nodeBuilder code to match. This is arguably harder to read. So it's possible that I should instead keep the nodeBuilder version as `typeof f` and make an exception for private name use.
@weswigham Any opinions on the right approach here? I was about to try the namespace merge, but I realised that I don't know how to make transformTopLevelDeclaration return two declarations. |
Returning two declarations in an array should be sufficient. A VisitResult is either a T, an undefined, or an array of T. |
@@ -952,6 +952,11 @@ namespace ts { | |||
} | |||
case SyntaxKind.FunctionDeclaration: { | |||
// Generators lose their generator-ness, excepting their return type | |||
if (resolver.isJSContainerFunctionDeclaration(input)) { | |||
const varDecl = createVariableDeclaration(input.name!, resolver.createTypeOfDeclaration(input, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined); | |||
const statement = createVariableStatement(needsDeclare ? [createModifier(SyntaxKind.DeclareKeyword)] : [], createVariableDeclarationList([varDecl], NodeFlags.Const)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use ensureModifiers(input)
instead of the needsDeclare
check here.
This makes the change smaller, overall.
Also improve emit style to match other namespace emit.
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined); | ||
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl])); | ||
}); | ||
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input), input.name!, createModuleBlock(declarations), NodeFlags.Namespace); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably needs to be ensureModifiers(input, isPrivate)
to inherit the scope's privacy correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Matters with a case like
namespace Foo {
function bar(): void {}
bar.num = 42;
export function foo() {
return bar;
}
}
@weswigham mind taking a look at the latest commit? I added your example, but the output looks wrong to me — I expected to see an object literal type, not |
Nope, it's perfect. The name shows up because it's visible internally at that location, which is all that matters. |
It does this by printing the type as an object literal type:
Appears in a d.ts as
It would also be possible to represent it as a namespace merge. I'm not sure which is better.
In order to avoid a private-name-used error (though I think it was actually unused), I also had to change the nodeBuilder code to match. This is arguably harder to read. So it's possible that I should instead keep the nodeBuilder version as
typeof f
and make an exception for private name use.Fixes #26485