Skip to content

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

Merged
merged 6 commits into from
Aug 27, 2018

Conversation

sandersn
Copy link
Member

It does this by printing the type as an object literal type:

function f() { }
f.p = 1

Appears in a d.ts as

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.

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.

Fixes #26485

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.
@sandersn
Copy link
Member Author

@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.

@weswigham
Copy link
Member

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));
Copy link
Member

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.

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);
Copy link
Member

@weswigham weswigham Aug 24, 2018

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.

Copy link
Member

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;
  }
}

@sandersn
Copy link
Member Author

@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 typeof ExpandoNamespace, for the type of a expando function that's not exported.

@weswigham
Copy link
Member

Nope, it's perfect. The name shows up because it's visible internally at that location, which is all that matters.

@sandersn sandersn merged commit 6419240 into master Aug 27, 2018
@sandersn sandersn deleted the declaration-emit-function-properties branch August 27, 2018 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants