-
-
Notifications
You must be signed in to change notification settings - Fork 834
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
Rewrite ItemList; update ItemList typings #3005
Conversation
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.
To me, "replace" implies a new content. Why not restrict "replace" to only do content, and have a separate "changePriority" method?
Removing the functionality of changing priority from the If I wanted to add a changePriority = (key: string, priority: number) => this.replace(key, { _useNewSyntax: true, priority }); I think of replace as replacing the entire item as a new one, rather than just the content. Maybe this needs some further discussion? I also think that being able to replace both the content and priority at once is nicer than doing two separate function calls with the same key. |
Well, what does "entire item" mean? I would argue that priority is moreso a property of the relation between items and their container than a property of the item itself. When someone asks how they can replace something with something else, that generally implies replacing in place, but keeping the same order. On a behavioral level, I think "replace" and "rearrange" make sense as separate, simple operations. Would be happy to hear counterarguments though.
I think that chained method calls alleviate this a bit. Absolutely agree that we shouldn't remove this functionality until 2.0. We could deprecate it though? |
Good idea. So...
Part of me wonders if we can take a jQuery approach and have something like |
Let's start with the first part, and look into |
1 similar comment
Let's start with the first part, and look into |
19620d0
to
5220da8
Compare
replace
syntaxThere 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'm looking over this again, and while I'm a fan of most of the changes (especially typing!), toObject
and toArray
seem way, way too complex for me
- This proxy prevents direct modification of the internal state to prevent people breaking the class.
Why can't we just return an object of key => content
? I don't think we should expose any internal state. This also lets us avoid all the complicated proxy stuff. On a side note, proxies are powerful, but we shouldn't use them unless we absolutely have to: it's a lot of added complexity.
.toArray()'s items are now proxied, meaning that values which were objects are no longer modified to add the itemName property. This is now provided through the Proxy.
If we're returning an array of primitives, we shouldn't have an itemName at all, so proxying is unnecessary. If we're returning an array of objects, we can use spread syntax to clone the object and cleanly attach the itemName. Proxies would be best to avoid.
js/src/common/utils/ItemList.ts
Outdated
* | ||
* Set when calling `.toArray()`. | ||
* | ||
* **NOTE:** If you modify the item list after `.toArray()` is called, |
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 don't think we should consider this to be part of the public API. Do we even need to set this on the internal representation?
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.
We don't use it internally, no. There's a chance someone somewhere uses it, but if you think we should just remove it, I'm fine with that.
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.
Let's remove it.
Because we need to be able to access the internal state of Items to correctly
We don't. If we have an const items = new ItemList<string | string[]>();
items.add('a', app.translator.trans('key1'), 10); // 'test'
items.add('b', app.translator.trans('key2', { test: 'hello' }), 9); // ['test', 'hello']
items.toArray();
// [ String('test') { itemName: 'key1' }, Array ['test', 'hello'] { itemName: 'key2' } ]
items.toArray(false);
// [ 'test', Array ['test', 'hello'] { itemName: 'key2' } ]
That will work fine for maps, but not other objects. If our ItemList holds dates, for example, all the date info is completely stripped when cloning with spread. It renders the ItemList completely useless. We only proxy the content, as that is what is returned in the array. If we use spread to clone the let x = new Date();
let y = { ...x, itemName: 'date1' };
console.log(y);
// { itemName: 'date1' } |
I still don't feel right about this: maybe we should tsignore and use the private I'm starting to think that the whole |
I'm not sure which way I'd prefer to do this:
...or as tuples. This way is more similar to the current interface, in the sense that we can do |
Now that I think about it, we cant do either because BC. Let's keep the proxy stuff for now, and hope we eventually come up with something better |
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 still don't feel right about this: maybe we should tsignore and use the private _items property directly, since the caller is within the ItemList code? Maybe a (as this) or something case could help there?
Bump on this btw
js/src/common/utils/ItemList.ts
Outdated
const val = otherItems[key]; | ||
|
||
if (val instanceof Item) { | ||
(this as ItemList<T | K>)._items[key] = val; |
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.
Doesn't this lose priority though?
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.
No, it's copying the whole Item class from the other ItemList and adding it to this one.
955d459
to
f8182b8
Compare
Rebased onto latest master. |
Turns out TS is more than fine with accessing private properties as long as its within the ItemClass' implementation of itself. |
Ok, I've updated the OP again to contain my latest changes. I think I'm pretty settled on these and the new API overall. It should be backwards compatible apart from:
|
This more closely matches our existing method names (`get()`)
de41908
to
2345641
Compare
Fixes #3030
Changes proposed in this pull request:
.get()
,.toArray()
, etc return the correct type based on the contents of the ItemLIstItemList
methods:setContent()
for setting the content of an itemsetPriority()
for setting the priority of an itemgetPriority()
for getting the priority of an itemreplace()
is now deprecatedsetContent(key, content)
methodsetPriority(key, priority)
methodItemList.items
is now deprecatedtoObject()
to get a map of itemNames to{ content, priority, itemName }
recordsItemList.toArray()
has a new parameter:keepPrimitives
true
will prevent content of primitive types, such as numbers/strings/etc., from being converted into Object representations of themselvesfalse
(default) will retain the current behaviour of converting to Object-ified typeskeepPrimitives
, are proxied to provide read-only access to anitemName
property.Confirmed
composer test
).Required changes: