Skip to content

Instantly share code, notes, and snippets.

@yackinn
Last active September 30, 2021 08:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yackinn/fa9fa44f672ec294dbd80607ddd27e38 to your computer and use it in GitHub Desktop.
Save yackinn/fa9fa44f672ec294dbd80607ddd27e38 to your computer and use it in GitHub Desktop.
Create dictionary function
import { isFunction } from 'lodash-es';
// todo may remove SymbolConstructor.iterator from item type
// record callbacks
type CallbackRecord<SourceItem, SourceKey, DictItem, DictKey> =
(item: SourceItem, key: SourceKey, index: number) => [DictKey, DictItem]
// array callbacks
type CallbackArray<SourceItem, DictItem, DictKey> =
(item: SourceItem, index: number) => [DictKey, DictItem]
// Combined
// type DictCallback<SourceItem, SourceKey, DictItem, DictKey> =
// CallbackRecord<SourceItem, SourceKey, DictItem, DictKey>
// | CallbackArray<SourceItem, DictItem, DictKey>
// todo RecordKey should also account for enum keys; any is needed as of today as it allows for enum keys
// https://github.com/Microsoft/TypeScript/pull/26797
// record or array without target
export function createDictionary<SourceItem,
SourceKey extends PropertyKey,
Source extends SourceItem[] | Record<SourceKey, SourceItem>,
DictItem,
DictKey extends PropertyKey>(
arrayOrRecord: Source,
callback: Source extends SourceItem[]
? CallbackArray<InferArrayValue<Source>, DictItem, DictKey>
: CallbackRecord<InferRecordValue<Source>, keyof Source, DictItem, DictKey>
): Record<DictKey, DictItem>;
// record or array with target
export function createDictionary<SourceItem,
SourceKey extends PropertyKey,
Source extends SourceItem[] | Record<SourceKey, SourceItem>,
TargetDictItem,
TargetDictKey extends PropertyKey>(
arrayOrRecord: Source,
target: Record<TargetDictKey, TargetDictItem>,
callback: Source extends SourceItem[]
? CallbackArray<InferArrayValue<Source>, TargetDictItem, TargetDictKey>
: CallbackRecord<InferRecordValue<Source>, keyof Source, TargetDictItem, TargetDictKey>
): Record<TargetDictKey, TargetDictItem>;
export function createDictionary<SourceItem,
SourceKey extends PropertyKey,
Source extends SourceItem[] | Record<SourceKey, SourceItem>,
TargetDictItem,
TargetDictKey extends keyof TargetDict,
TargetDict extends Record<TargetDictKey, TargetDictItem>
| CallbackArray<SourceItem, InferRecordValue<TargetDict>, TargetDictKey>
| CallbackArray<SourceItem, DictItem, DictKey>
| CallbackRecord<SourceItem, keyof Source, InferRecordValue<TargetDict>, TargetDictKey>
| CallbackRecord<SourceItem, keyof Source, DictItem, DictKey>,
DictItem,
DictKey extends PropertyKey>(
arrayOrRecord: Source,
targetOrCallback: TargetDict,
callback?: Source extends SourceItem[]
? TargetDict extends Record<any, any>
? CallbackArray<SourceItem, InferRecordValue<TargetDict>, TargetDictKey>
: CallbackArray<SourceItem, DictItem, DictKey>
: TargetDict extends Record<any, any>
? CallbackRecord<SourceItem, keyof Source, InferRecordValue<TargetDict>, TargetDictKey>
: CallbackRecord<SourceItem, keyof Source, DictItem, DictKey>
): Record<DictKey, DictItem> | TargetDict {
if (!arrayOrRecord) {
return;
}
let dictionary;
if (isFunction(targetOrCallback)) {
callback = targetOrCallback;
dictionary = {} as Record<DictKey, DictItem>;
}
else {
dictionary = targetOrCallback as TargetDict;
}
if (isArray(arrayOrRecord) && isFunction(targetOrCallback)) {
arrayOrRecord.forEach((item, index) => {
const result = callback(item, index);
dictionary[result[0]] = result[1];
});
}
else {
Object.entries<SourceItem>(arrayOrRecord).forEach(([key, item], index) => {
const result = callback(item, key, index);
dictionary[result[0]] = result[1];
});
}
return dictionary;
}
// function isDictCallback(item): item is DictCallback<any, any, any, any> {
// return isFunction(item);
// }
export function dictionary<K extends PropertyKey, T>(): Record<K, T> {
return {} as Record<K, T>;
}
export function isArray<T>(value: T[] | Record<PropertyKey, T>): value is T[] {
return Array.isArray(value);
}
export function isRecord<T>(value: T[] | Record<PropertyKey, T> | ((...any: any) => any)): value is Record<any, any> {
return !Array.isArray(value) && !isFunction(value);
}
type InferArrayValue<T> = T extends Array<infer U> ? U : T;
type InferRecordValue<T> = T extends Record<any, infer U> ? U : T
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment