GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Add new special assignment kinds for recognizing Object.defineProperty calls by weswigham · Pull Request #27208 · microsoft/TypeScript Conversation
|
|
|
||
| function getAssignmentDeclarationKindWorker(expr: BinaryExpression): AssignmentDeclarationKind { | ||
| export function isBindableObjectDefinePropertyCall(expr: CallExpression): expr is BindableObjectDefinePropertyCall { | ||
| return !(length(expr.arguments) !== 3 || |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
! ... !== .. || ? Why not write it as ... === ... && ?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Also, I thought you said the third one was optional? I guess we won't be able to get the type in that case, but we could still bind the property with type any.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It's not optional, it just has a few different shapes it can take.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| // Variables declared with 'const' | ||
| // Get accessors without matching set accessors | ||
| // Enum members | ||
| // JS Assignments with writable false or no setter |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
pedantically (since I spent a day thinking about terms), it's better to say // define-property assignments with writable false or no setter. This parallels terminology of things that are parllel, like "this-property assignments" or "prototype assignments".
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| /** @internal */ | ||
| export type BindableObjectDefinePropertyCall = CallExpression & { arguments: { 0: EntityNameExpression, 1: StringLiteralLike | NumericLiteral, 2: ObjectLiteralExpression } }; | ||
|
|
||
|
|
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
extra newline
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| case SyntaxKind.PropertyAssignment: | ||
| return init.initializer; | ||
| case SyntaxKind.ShorthandPropertyAssignment: | ||
| case SyntaxKind.MethodDeclaration: |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
which ones are allowed to be methods? get? set? value?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Get and set often are. Value can be, it'd be the same as a property with a function expression value, though.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think this function is unused in my current implementation, though.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| return AssignmentDeclarationKind.None; | ||
| } | ||
| const entityName = expr.arguments[0]; | ||
| if ((isIdentifier(entityName) && entityName.escapedText === "exports") || (isPropertyAccessExpression(entityName) && isIdentifier(entityName.expression) && entityName.expression.escapedText === "module" && entityName.name.escapedText === "exports")) { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
newline needed in here somewhere
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
#6651 definitely is included here. At least for JS. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I think I need extra handling to cover the prototype assignment case as in |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Nathan Shively-Sanders (@sandersn) I've added support for prototype property assignments. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| case AssignmentDeclarationKind.None: | ||
| break; // Nothing to do | ||
| default: | ||
| return Debug.fail("Unknown call expression assignment declaration kind"); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Debug.assertNever is better here I think.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
assignmentKind has all the non-object-define values still "possible" (they're not, because it's a call expression and not a binary expression) and so isn't never; so not quite?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| return AssignmentDeclarationKind.None; | ||
| } | ||
| const entityName = expr.arguments[0]; | ||
| if ((isIdentifier(entityName) && entityName.escapedText === "exports") || |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
maybe we should have a is[Module]Exports utility since this is repeated for the ExportsProperty case below.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Hilariously enough, 10 lines up we already have one, with exactly what i was going to name it.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| function getInitializerTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol: Symbol | undefined, expression: BinaryExpression | CallExpression, kind: AssignmentDeclarationKind) { | ||
| if (isCallExpression(expression)) { | ||
| if (resolvedSymbol) { | ||
| return getTypeOfSymbol(resolvedSymbol); // This shouldn't happen except under some hopefully forbidden merges of export assignments and object define assignments |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
is there a test for this case?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
AFAIK I can't construct something that can actually hit this codepath currently (since something like Object.defineProperty(module, "exports", { value: "no" }) won't be bound to the module in the first place); but I wanna avoid crashing and burning if we change something, and this seems reasonable (ignoring the reassignment). I'll add a test with similar content that could trigger it if we ever do start binding it a bit differently, though.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
| isObjectLiteralExpression(container.parent.parent) && | ||
| isCallExpression(container.parent.parent.parent) && | ||
| container.parent.parent.parent.arguments[2] === container.parent.parent && | ||
| getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty) { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
(this applies to all the cases in this function) Would it be possible, and more efficient, to just check that parent x 3 exists and then just check the result of getAssignmentDeclarationKind? I think the rest of the predicate is duplicated with it.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Not quite - these are actually some extra constraints which ask that the third argument be specifically an object literal (rather than anything we might be able to pull a type from), to inject a this type into the method defined in it, even if Object.defineProperty's signature lacks a strong this (and, in fact, it does lack one).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| case AssignmentDeclarationKind.ObjectDefinePropertyValue: | ||
| case AssignmentDeclarationKind.ObjectDefinePropertyExports: | ||
| case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: | ||
| return Debug.fail("Unimplemented"); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
"Not yet implemented" or "Does not apply"? Isn't it the latter?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Yea, definitely the later.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Some questions and suggestions, plus I need to look at the tests.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Can you see what happens with the user tests? (and maybe RWC, although I don't think there's much JS there.) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
|
||
| ==== tests/cases/conformance/jsdoc/index.js (0 errors) ==== | ||
| const x = {}; | ||
| Object.defineProperty(x, "name", { value: "Charles", writable: true }); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
you should have a value test that leaves off writable, if that's allowed. Actually, you should have a test with value left out too. And maybe a test with some of the properties we don't care about?
Also a test with non-literals, just in case that hurts our ... error reporting or something?
According to MDN's Object.defineProperty page, we should have an error if both get/set and value are present. I didn't see a test for that either.
Also, who spells 'writeable' as 'writable'?
Later:everybody else, it turns out.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Nathan Shively-Sanders (@sandersn) I've replied to or addressed all of your comments; how'd you feel about this now? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Looks good except for four things:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
The function is still typechecked as a function call, so that aughta still be happening provided the |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
OK, then I guess we should consider changing it afterward. It would probably break some code, though. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Wesley Wigham (@weswigham) It would be nice to get this one in. Will you have time to add those tests some time? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Yeah, I'll take some time to add them today. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Sorry to comment on a long closed issue, but is this also implemented for |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Nope. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Does this still work? It's not for me in VScode: Version: 1.59.0 Suppose the following code:test.ts: const something = { somethingValue: 'test' } Object.defineProperty(something, 'definedProperty', { value: 'hello' }) export default something test2.ts: import Thing from './test' Thing.somethingValue // this is okay Thing.definedProperty // this will have red curly underline So why does |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
We only recognize them in .js files, not .ts. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
I see. But because it wasn't working in JS, that's why I converted it to TS to see if it works. I reverted the files to JS, and the screenshot below shows that it wasn't able to see the property defined using #defineProperty: |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I think it's time for a .ts implementation too! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
using Visual Studio Code 1.66.0 I can confirm that Object.defineProperty appears to be not recognized |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
JavaScript IntelliSense Should Recognize DefineProperty Types are not imported properly for packages that use exports.default. Salsa does not discover properties defined with Object.defineProperty
There was an error while loading. Please reload this page.