Skip to content

Commit

Permalink
feat(transmute): infer transmuter extra param based on transmute call
Browse files Browse the repository at this point in the history
- Add conditional type inference that matches transmute usage
- When extra is provided to transmute, it's non-optional in transmuters
- When extra is omitted from transmute, transmuter can't access extra
- Improve readability with clearer variable names and logical grouping

The extra parameter in transmuters now matches how transmute is called:
present and required when extra is provided, absent when it's not.
  • Loading branch information
tonioriol committed Oct 31, 2024
1 parent a9fc738 commit c83b1c0
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('transmute', () => {
{
to: 'location',
from: ({ source, extra }) =>
`${source.address.city}, ${source.address.country}${extra?.separator}`
`${source.address.city}, ${source.address.country}${extra.separator}`
}
]

Expand Down
22 changes: 15 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,23 @@ export * from './types'
* @param extra - Optional extra data to pass to mutation functions
* @returns Transmuted object matching Target type
*/
export const transmute = <Source, Target, Extra = unknown>(
export const transmute = <Source, Target, Extra>(
schema: Schema<Source, Target, Extra>[],
source: Source,
extra?: Extra
): Target =>
schema.reduce<Target>(
(acc, { from, to }) => ({
...acc,
[to]: typeof from === 'function' ? from({ source, extra }) : source[from]
}),
): Target => {
return schema.reduce<Target>(
(acc, { from, to }) => {

const isFunction = typeof from === 'function'
const extraData = extra ? { extra } : {}
const value = isFunction ? (from as Function)({ source, ...extraData }) : source[from]

return {
...acc,
[to]: value
}
},
{} as Target
)
}
13 changes: 4 additions & 9 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
* @template Source - The source type being transmuted from
* @template Extra - Type of additional data for transmutation
*/
export type TransmuteFnArgs<Source, Extra> = {
/** The source object being transmuted */
source: Source
/** Optional extra data to assist with transmutation */
extra?: Extra
}
export type TransmuteFnArgs<Source, Extra> = Extra extends undefined | never
? { source: Source }
: { source: Source; extra: Extra }

/**
* Function that performs a custom transmutation on a source object
Expand All @@ -33,11 +30,9 @@ type AssignableKeys<Source, Target, TargetKey extends keyof Target> = {
* @template Target - The target type being transmuted to
* @template Extra - Type of additional data for transmutation
*/
export type Schema<Source, Target, Extra = unknown> = {
export type Schema<Source, Target, Extra = undefined> = {
[TargetKey in keyof Target]: {
/** Target property key */
to: TargetKey
/** Source property key for direct mapping or a custom transmutation function */
from: AssignableKeys<Source, Target, TargetKey> | TransmuteFn<Source, Target, TargetKey, Extra>
}
}[keyof Target]

0 comments on commit c83b1c0

Please sign in to comment.