Skip to content

Commit 912ca07

Browse files
committed
well damn, that worked great
1 parent 57976cd commit 912ca07

3 files changed

Lines changed: 44 additions & 4 deletions

File tree

test/renameKeys.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { expectAssignable, expectType } from 'tsd';
2+
3+
import { __, renameKeys } from '../es';
4+
5+
expectType<{ bar: number; other: string }>(renameKeys({ foo: 'bar' })({ foo: 123, other: 'abc' }));
6+
expectType<{ foo: number; blah: string }>(renameKeys({ other: 'blah' })({ foo: 123, other: 'abc' }));
7+
8+
expectType<{ bar: number; other: string }>(renameKeys(__, { foo: 123, other: 'abc' })({ foo: 'bar' }));
9+
expectType<{ foo: number; blah: string }>(renameKeys(__, { foo: 123, other: 'abc' })({ other: 'blah' }));
10+
11+
expectType<{ bar: number; other: string }>(renameKeys({ foo: 'bar' }, { foo: 123, other: 'abc' }));
12+
expectType<{ foo: number; blah: string }>(renameKeys({ other: 'blah' }, { foo: 123, other: 'abc' }));
13+
14+
const nonConstObj = { foo: 'bar' };
15+
16+
const what = renameKeys(nonConstObj, { foo: 123, other: 'abc' });
17+
// ^?
18+
// @ts-expect-error - I have no idea why declaring the type throws an error, but it can be calculated above
19+
expectAssignable<{ [x: string]: number; other: string; }>(what);

types/renameKeys.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { Placeholder } from './util/tools';
1+
import { Placeholder, Prettify, Remap } from './util/tools';
22

33
// renameKeys(mapping)(obj)
4-
export function renameKeys(mapping: Record<string, string>): <T>(obj: Record<string, T>) => Record<string, T>;
4+
export function renameKeys<const U extends Record<PropertyKey, string>>(mapping: U): <T extends Record<keyof U, unknown>>(obj: T) => Prettify<Omit<T, keyof U> & Remap<T, U>>;
55
// renameKeys(__, obj)(mapping)
6-
export function renameKeys<T>(__: Placeholder, obj: Record<string, T>): (mapping: Record<string, string>) => Record<string, T>;
6+
export function renameKeys<T>(__: Placeholder, obj: T): <const U extends Partial<Record<keyof T, string>>>(mapping: U) => Prettify<Omit<T, keyof U> & Remap<T, U>>;
77
// renameKeys(mapping, obj)
8-
export function renameKeys<T>(mapping: Record<string, string>, obj: Record<string, T>): Record<string, T>;
8+
export function renameKeys<T, const U extends Partial<Record<keyof T, string>>>(mapping: U, obj: T): Prettify<Omit<T, keyof U> & Remap<T, U>>;

types/util/tools.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,3 +520,24 @@ export type NonEmptyArray<T> = [T, ...T[]];
520520
* <created by @harris-miller>
521521
*/
522522
export type ReadonlyNonEmptyArray<T> = readonly [T, ...T[]];
523+
524+
/**
525+
* Prettify type into an object literal
526+
* <created by @harris-miller>
527+
*/
528+
export type Prettify<T> = {[KeyType in keyof T]: T[KeyType]} & {};
529+
530+
type TuplesFromObject<T> = {
531+
[P in keyof T]: [P, T[P]];
532+
}[keyof T];
533+
534+
type GetKeyByValue<T, V> =
535+
TuplesFromObject<T> extends infer TT
536+
? TT extends [infer P, V]
537+
? P
538+
: never
539+
: never;
540+
541+
export type Remap<T, U extends { [P in keyof T]?: string }> = {
542+
[P in NonNullable<U[keyof U]>]: T[GetKeyByValue<U, P>];
543+
};

0 commit comments

Comments
 (0)