This repository was archived by the owner on Mar 31, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 100
fix(typescript): handle property accessors correctly #247
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
typescript/mocks/readTypeScriptModules/gettersAndSetters.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
export class Test { | ||
get foo1(): string { return null; } | ||
/** foo1 setter */ | ||
set foo1(value: string) { /* do nothing */} | ||
|
||
set foo2(value: string) { /* do nothing */} | ||
/** foo2 getter */ | ||
get foo2(): string { return null; } | ||
|
||
/** bar getter */ | ||
get bar(): number { return null; } | ||
|
||
/** qux setter */ | ||
set qux(value: object) { /* do nothing */ } | ||
|
||
/** This has no explicit getter return type */ | ||
get noType() { return 'x'; } | ||
/** So we get it from the setter instead */ | ||
set noType(value: string) { /**/ } | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Declaration, SignatureDeclaration, TypeChecker } from 'typescript'; | ||
import { getDeclarationTypeText } from '../services/TsParser/getDeclarationTypeText'; | ||
import { getParameters } from '../services/TsParser/getParameters'; | ||
import { encodeAnchor } from '../utils/encodeAnchor'; | ||
import { MethodMemberDoc } from './MethodMemberDoc'; | ||
import { PropertyMemberDoc } from './PropertyMemberDoc'; | ||
|
||
/** | ||
* This represents a getter or setter overload of an accessor property. | ||
* There will be a PropertyMemberDoc that contains these docs. | ||
*/ | ||
export class AccessorInfoDoc extends MethodMemberDoc { | ||
docType = `${this.accessorType}-accessor-info`; | ||
name = `${this.propertyDoc.name}:${this.accessorType}`; | ||
id = `${this.propertyDoc.id}:${this.accessorType}`; | ||
aliases = this.propertyDoc.aliases.map(alias => `${alias}:${this.accessorType}`); | ||
anchor = encodeAnchor(this.name); | ||
|
||
constructor(public accessorType: 'get'|'set', public propertyDoc: PropertyMemberDoc, declaration: Declaration, basePath: string, namespacesToInclude: string[]) { | ||
super(propertyDoc.containerDoc, propertyDoc.symbol, declaration, basePath, namespacesToInclude, false); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,35 @@ | ||
import { Declaration, GetAccessorDeclaration, SetAccessorDeclaration, SignatureDeclaration, Symbol, SyntaxKind } from 'typescript'; | ||
import { getDeclarationTypeText } from "../services/TsParser/getDeclarationTypeText"; | ||
import { getParameters } from '../services/TsParser/getParameters'; | ||
import { encodeAnchor } from '../utils/encodeAnchor'; | ||
import { AccessorInfoDoc } from './AccessorInfoDoc'; | ||
import { ContainerExportDoc } from './ContainerExportDoc'; | ||
import { MemberDoc } from './MemberDoc'; | ||
|
||
export class PropertyMemberDoc extends MemberDoc { | ||
name = this.symbol.name; | ||
anchor = encodeAnchor(this.name); | ||
id = `${this.containerDoc.id}.${this.name}`; | ||
aliases = this.containerDoc.aliases.map(alias => `${alias}.${this.name}` ); | ||
getAccessor: AccessorInfoDoc | null; | ||
setAccessor: AccessorInfoDoc | null; | ||
|
||
constructor( | ||
containerDoc: ContainerExportDoc, | ||
symbol: Symbol, | ||
declaration: Declaration | null, | ||
getAccessorDeclaration: GetAccessorDeclaration | null, | ||
setAccessorDeclaration: SetAccessorDeclaration | null, | ||
basePath: string, | ||
namespacesToInclude: string[], | ||
isStatic: boolean, | ||
) { | ||
super(containerDoc, symbol, (declaration || getAccessorDeclaration || setAccessorDeclaration)!, basePath, namespacesToInclude, isStatic); | ||
|
||
// If this property has accessors then compute the type based on that instead | ||
this.getAccessor = getAccessorDeclaration && new AccessorInfoDoc('get', this, getAccessorDeclaration, basePath, namespacesToInclude); | ||
this.setAccessor = setAccessorDeclaration && new AccessorInfoDoc('set', this, setAccessorDeclaration, basePath, namespacesToInclude); | ||
this.type = this.type || this.setAccessor && this.setAccessor.parameters[0].split(/:\s?/)[1] || ''; | ||
this.content = this.content || this.setAccessor && this.setAccessor.content || ''; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
If we have passed in
declaration
orgetAccessorDeclaration
then we will have extracted the type from one of those, if possible.Uh oh!
There was an error while loading. Please reload this page.
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.
Yeah that's true. On Material we have a small workaround for this, but it still uses the declaration to retrieve the type. See here
Uh oh!
There was an error while loading. Please reload this page.
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.
Might be worth to also check how the description of the getter/setter is being handled. I noticed that the description is only being read from one place.
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.
So the getter and setter are docs in their own right, so their documentation should be processed for jsdoc tags, etc. You can then access them via the
member.getAccessor
andmember.setAccessor
for use in the property template.This is similar to how overloads are being dealt with. With overloads we extract the content of the "actual" function for the member doc but then attach the content for each of the overload declarations to the overloads for that member.
In the case of a property with a getter and setter, we extract the content from the first declaration that is defined from
[declaration, getter, setter]
. It would seem to me more common to put the documentation (if there is only one) on the getter not the setter YMMV. But if you do put it only on the setter then you could easily get around this by doing something like:Something like:
Is this too unreasonable? Do you really put documentation on the setter only?
Uh oh!
There was an error while loading. Please reload this page.
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.
Not really, on Material I remember seeing accessors that have the descriptions on a
setter
or on thegetter
and I want to make sure we don't need to enforce something here.For the description, for me it makes sense to have a
description
property on the "MemberDoc". The description there should be retrieved in a similar way as the type, because it can be either on the getter or setter.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.
OK, I'll transfer that from the relevant accessor too.
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.
Done PTAL
Uh oh!
There was an error while loading. Please reload this page.
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.
Just tested it locally and the types seem to work fine now. For the descriptions, I'm not sure what's different to
content
is? When debugging most of our accessors in Material, they don't seem to have acontent
either.Isn't there a way to set the
description
as well, based on the two cases I described above?This is the code-snippet we currently use in Material to receive the proper description for an accessor.
https://github.com/angular/material2/blob/4d97271786855598cfd18921641d5ffaafa079d8/tools/dgeni/common/dgeni-accessors-parse.ts#L51-L54
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.
Remember that this processor runs before the jsdic processing happens. The content field contains the raw content. After jsdoc runs there will be a description property too
Uh oh!
There was an error while loading. Please reload this page.
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.
Hmm I'm not sure why theDiscussed on Slack.content
is empty then. For me likely every accessor document has acontent
that is empty.