-
Notifications
You must be signed in to change notification settings - Fork 272
Convert number-format to TypeScript #75
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,19 +11,30 @@ interface ItemWithValue<T> { | |
} | ||
|
||
interface ItemWithLoader<T> { | ||
loader: () => T | Promise<T>; | ||
loader: () => T; | ||
} | ||
|
||
export interface RegistryConfig { | ||
name?: string; | ||
overwritePolicy?: OverwritePolicy; | ||
} | ||
|
||
export default class Registry<V> { | ||
/** | ||
* Registry class | ||
* | ||
* Can use generic to specify type of item in the registry | ||
* @type V Type of value | ||
* @type W Type of value returned from loader function when using registerLoader(). | ||
* W can be either V, Promise<V> or V | Promise<V> | ||
* Set W=V when does not support asynchronous loader. | ||
* By default W is set to V | Promise<V> to support | ||
* both synchronous and asynchronous loaders. | ||
*/ | ||
export default class Registry<V, W extends V | Promise<V> = V | Promise<V>> { | ||
name: string; | ||
overwritePolicy: OverwritePolicy; | ||
items: { | ||
[key: string]: ItemWithValue<V> | ItemWithLoader<V>; | ||
[key: string]: ItemWithValue<V> | ItemWithLoader<W>; | ||
}; | ||
|
||
promises: { | ||
|
@@ -70,7 +81,7 @@ export default class Registry<V> { | |
return this; | ||
} | ||
|
||
registerLoader(key: string, loader: () => V | Promise<V>) { | ||
registerLoader(key: string, loader: () => W) { | ||
const item = this.items[key]; | ||
const willOverwrite = | ||
this.has(key) && (('loader' in item && item.loader !== loader) || 'value' in item); | ||
|
@@ -89,7 +100,7 @@ export default class Registry<V> { | |
return this; | ||
} | ||
|
||
get(key: string): V | Promise<V> | undefined { | ||
get(key: string): V | W | undefined { | ||
const item = this.items[key]; | ||
if (item !== undefined) { | ||
if ('loader' in item) { | ||
|
@@ -109,7 +120,7 @@ export default class Registry<V> { | |
} | ||
const item = this.get(key); | ||
if (item !== undefined) { | ||
const newPromise = Promise.resolve(item); | ||
const newPromise = Promise.resolve(item) as Promise<V>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this and the function return type not be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line is always a promise. |
||
this.promises[key] = newPromise; | ||
|
||
return newPromise; | ||
|
@@ -120,7 +131,7 @@ export default class Registry<V> { | |
|
||
getMap() { | ||
return this.keys().reduce<{ | ||
[key: string]: V | Promise<V> | undefined; | ||
[key: string]: V | W | undefined; | ||
}>((prev, key) => { | ||
const map = prev; | ||
map[key] = this.get(key); | ||
|
@@ -148,22 +159,22 @@ export default class Registry<V> { | |
return Object.keys(this.items); | ||
} | ||
|
||
values(): Array<V | Promise<V> | undefined> { | ||
values(): (V | W | undefined)[] { | ||
return this.keys().map(key => this.get(key)); | ||
} | ||
|
||
valuesAsPromise(): Promise<V[]> { | ||
return Promise.all(this.keys().map(key => this.getAsPromise(key))); | ||
} | ||
|
||
entries(): Array<{ key: string; value: V | Promise<V> | undefined }> { | ||
entries(): { key: string; value: V | W | undefined }[] { | ||
return this.keys().map(key => ({ | ||
key, | ||
value: this.get(key), | ||
})); | ||
} | ||
|
||
entriesAsPromise(): Promise<Array<{ key: string; value: V }>> { | ||
entriesAsPromise(): Promise<{ key: string; value: V }[]> { | ||
const keys = this.keys(); | ||
|
||
return Promise.all(keys.map(key => this.getAsPromise(key))).then(values => | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,15 +3,18 @@ import createD3NumberFormatter from './factories/createD3NumberFormatter'; | |
import NumberFormats from './NumberFormats'; | ||
import NumberFormatter from './NumberFormatter'; | ||
|
||
export default class NumberFormatterRegistry extends RegistryWithDefaultKey<NumberFormatter> { | ||
export default class NumberFormatterRegistry extends RegistryWithDefaultKey< | ||
NumberFormatter, | ||
NumberFormatter | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does the it seems a little burdensome for the users to always have to specify the same type 2wice 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you set |
||
> { | ||
constructor() { | ||
super({ | ||
initialDefaultKey: NumberFormats.SI, | ||
name: 'NumberFormatter', | ||
}); | ||
} | ||
|
||
get(formatterId?: string): NumberFormatter { | ||
get(formatterId?: string) { | ||
const targetFormat = `${formatterId || this.defaultKey}`.trim(); | ||
|
||
if (this.has(targetFormat)) { | ||
|
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.
for simplicity could we just say that this has to be
V | Promise<V>
? it seems like we shouldn't really need to support anything beyond that since ultimately it should matchV
right?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 agree with the added complexity. The high-level idea is to be able to define synchronous registry. I am considering adding a subclass of
Registry
just to alias and hide this multiple generics.W
affect the.get()
function in particular if the returned value is always the value or can also be a promise of the value. If it can be either promise of value then the subclass has to always consider if the value is promise or not. Using theW
generic add these benefits:loader
is not async..get
is not a promise simplifies the subclass operations. (Not having to manually override/cast)