Skip to content
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

Reflect.getOwnMetadata gets metadata for parents in Typescript #24

Closed
doktordirk opened this issue Apr 29, 2016 · 20 comments
Closed

Reflect.getOwnMetadata gets metadata for parents in Typescript #24

doktordirk opened this issue Apr 29, 2016 · 20 comments

Comments

@doktordirk
Copy link
Contributor

doktordirk commented Apr 29, 2016

edit:
Current Reflect polyfill doesn work for child classes in typescript since Object.hasOwnProperty(key) returns the parent if applicable


old message:
@cmichaelgraham following up on aurelia/metadata#33

class x {
  meta;
}
class y extends x{}

y.hasOwnProperty('meta') should be false.

this works as specified in es6 but not for typescript where current version yields true.

https://github.com/aurelia/polyfills/blob/master/src/reflect.js#L21

let metadataContainer = target.hasOwnProperty(metadataContainerKey) ? target[metadataContainerKey] : (target[metadataContainerKey] = {});
let targetContainer = metadataContainer[targetKey] || (metadataContainer[targetKey] = {}); 

if target.hasOwnProperty gives wrongly true for child classes, the parent target[metadataContainerKey] is used for metadataContainer. and since targetKey is undefined and the parent has a metadataContainer['undefined'] the parents targetContainer is used instead of a new one.

sorry if i'm not clear enough, but finding the issue wasn't particular easy. m mushy in the head.
point begin: hasOwnProperty isn't behaving right for TS

@EisenbergEffect
Copy link
Contributor

Would you be interested to submit a PR to fix this? 😄

@doktordirk
Copy link
Contributor Author

hell no 😄
that'll be far over my head i think. (though i'll have a peak nonetheless)

@doktordirk
Copy link
Contributor Author

@EisenbergEffect i assume microsoft/TypeScript#1601 is the issue. something different in the extends impelemtation of TS

@doktordirk doktordirk changed the title hasOwnProperty gives wrong result for inherited property in Typescript Reflect.getOwnMetadata gets metadata for parents in Typescript Apr 30, 2016
@doktordirk
Copy link
Contributor Author

as it seems difficult to distinguish parent and child properties in typescript, the only/best solution would be to use/follow https://github.com/rbuckton/ReflectDecorators/blob/master/Reflect.js . they keep a weapmap based on the target for all metadatas. i'm not sure atm if there is another solution than a seperate metadata list

@doktordirk
Copy link
Contributor Author

@EisenbergEffect i'm still sortof battling with current Reflect poyfill. i tired to look up the specifications, but didn't find it for the used methods. only found https://tc39.github.io/ecma262/#sec-reflection which is different from whats used here!?

@EisenbergEffect
Copy link
Contributor

The metadata methods used here are part of the Metadata proposal for ES Next.

@doktordirk
Copy link
Contributor Author

@EisenbergEffect
that seem to be quite far from getting implemented. it's not even yet proposed and the original specs have been deleted!

see some discussion here zloirock/core-js#152

@EisenbergEffect
Copy link
Contributor

I submitted an issue to @rbuckton 's repo. We'll see what they say. We do need to associate metadata with classes, so it's going to stay in some form. The only question is whether we need to update the implementation in some way.

@doktordirk
Copy link
Contributor Author

since it's not working for typescript as it is, something has to be done. i see three options:

  • tell typescript user to use there own polyfill (though i didn't manage that yet)
  • use the implementation from eg https://github.com/gdi2290/es7-reflect-metadata
  • make a hacky version by just adding/using target.name to/for the target key. (as opposed to leaving the key at undefinedas per Reflect spez for class metadata, i think)

@EisenbergEffect
Copy link
Contributor

Have you tried the name hack...when the code is minified?

@doktordirk
Copy link
Contributor Author

doktordirk commented May 2, 2016

unminified worked for plugins when calling (aurelia-)metadata.getOrCreateOwn(Metadata.key, Metadata, target**, target.name**);

had a quick try early on with getOrCreateOwn(metadataKey: string, Type: Function, target: Function, targetKey=target.name: string): Object; which cause errors for TS.

didn' try yet Reflect.defineMetadata = function(metadataKey, metadataValue, target, targetKey=target.name) or alike nor minified.

but i'll play around a bit

ps: minification shouldn't matter with this approach anyways

@doktordirk
Copy link
Contributor Author

@EisenbergEffect @cmichaelgraham
while basically working just fine, it unfortunately creates new issues for Typescript with metadata.get

get(metadataKey: string, target: Function, targetKey?: string): Object {
    if (!target) { return undefined; }
    let result = metadata.getOwn(metadataKey, target, targetKey);
    return result === undefined ? metadata.get(metadataKey, Object.getPrototypeOf(target), targetKey) : result;
  },

that worked for TS before, since metadata.getOwn allways did get from the parent anyways.
if that's fixed for TS, then Object.getPrototypeOf(target) should be used to get the parents metadata if applicable, but which, surprise surprise, doesn't work with TS's extends. (so, coming back again to aforementioned Microsoft/TypeScript 1601)

that starts to beg the question, whether it wouldn't be better to force TS to use a standard compliant extends generally.

@doktordirk
Copy link
Contributor Author

i found another possible solution: let typescript target es6 instead of es5. works with current edge/chrome/firefox. obviously older browser will get problems. dunno if chaining babel for 6to5 would works

@EisenbergEffect
Copy link
Contributor

@doktordirk Do you have any other thoughts on this?

@doktordirk
Copy link
Contributor Author

@EisenbergEffect since it'll be solved if the typescript to es6 transpiler is used, it'll be a no issue at some stage. meanwhile, i could add a hint with a workaround to the readme or somewhere else you point me to

@doktordirk
Copy link
Contributor Author

ps: my commit message in our plugins reads like:

Typescript's 'extends' is on purpose not according to specifications. Therefore, Reflects usage with targettKey===undefinded of hasOwnProperty(targettKey) returns true for a parent property 'undefined' (The derived class doesn't have that at this point, thus false should have been returned).

A simple fix for us is not to use the key 'undefined' (as per specification) in this case, but use a key on basis of the class name. Since they are different, the faulty 'extends' doesn't propose an issue

so, instead of:

import {metadata} from 'aurelia-metadata';

export class OrmMetadata {
  static forTarget(target) {
    return metadata.getOrCreateOwn(Metadata.key, Metadata, target);
  }
}

use

import {metadata} from 'aurelia-metadata';

export class OrmMetadata {
  static forTarget(target) {
    return metadata.getOrCreateOwn(Metadata.key, Metadata, target, target.name);
  }
}

@EisenbergEffect
Copy link
Contributor

Hmm. A note would be great...I'm just not sure where it should go. Do you have any thoughts on that. Where would you expect to find it as a community member?

@doktordirk
Copy link
Contributor Author

I guess metadata be best. not that many will use it themself. i.ll try do PR something. on a general note. Maybe typescript tests should be included somehow

@doktordirk
Copy link
Contributor Author

@EisenbergEffect
added it to the docblock, so it appears in the HUBs api docs. I think that would be the best place.
aurelia/metadata#38

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants