Skip to content

Instantly share code, notes, and snippets.

@zRains
Last active July 5, 2024 06:26
Show Gist options
  • Save zRains/9e68a35649af6de7463fd2d1d068c823 to your computer and use it in GitHub Desktop.
Save zRains/9e68a35649af6de7463fd2d1d068c823 to your computer and use it in GitHub Desktop.
type StrLen<T extends string, R extends Array<string> = []> = T extends `${infer C}${infer P}`
? StrLen<P, [...R, C]>
: R['length']
type StrSplit<T extends string, S extends string, R extends Array<string> = []> = T extends `${infer X}${S}${infer Y}`
? StrSplit<Y, S, StrLen<X> extends 0 ? R : [...R, X]>
: StrLen<T> extends 0
? R
: [...R, T]
type TailProp<T extends string> = T extends `${string}.${infer U}` ? TailProp<U> : T
type PickSource<T extends Array<string>, S extends Record<string, any> = {}> = {
[K in T[number] as TailProp<K>]: PickSourceDeep<K, S>
}
type ParseInt<T> = T extends `${infer N extends number}` ? N : never
type PickSourceDeep<
T extends string,
S extends Record<string, any> | Array<unknown> = {},
__Sp extends Array<string> = StrSplit<T, '.'>,
__R = never,
> = __Sp extends [infer C, ...infer R]
? S extends Array<unknown>
? PickSourceDeep<
never,
NonNullable<Extract<S[ParseInt<C>], Array<unknown> | Record<string, any>>>,
R extends Array<string> ? R : [],
S[ParseInt<C>]
>
: C extends keyof S
? PickSourceDeep<
never,
NonNullable<S[C]> extends Record<string, any> ? NonNullable<S[C]> : never,
R extends Array<string> ? R : [],
S[C]
>
: unknown
: __R
function pickProps<T extends Record<string, any>, K extends Array<Extract<keyof T, string>> | Array<string>>(
source: T,
keys: K,
): Partial<PickSource<K, Required<T>>> {
const result: Partial<PickSource<K, Required<T>>> = Object.create(null)
keys.forEach((key) => {
if (typeof key === 'string') {
let keyPath = key.split('.')
Reflect.set(
result,
keyPath[keyPath.length - 1],
keyPath.reduce<unknown>((s, k) => (typeof s === 'undefined' ? s : Reflect.get(s!, k)), source),
)
} else {
Reflect.set(result, key, Reflect.get(source, key))
}
})
return result
}
@zRains
Copy link
Author

zRains commented Jul 5, 2024

Usage:

interface UU {
  name: string
  age: number
  data: Array<{ oo: string; ko: boolean }>
  addr: {
    pa: boolean
    pp: {
      kk: string
      ee: {
        oi: number
      }
    }
  }
}

const ddd: Partial<UU> = {
  name: 'zrian',
  age: 19,
  data: [
    { oo: 'asd', ko: true },
    { oo: 'asdas', ko: false },
  ],
  addr: {
    pa: true,
    pp: {
      kk: 'asdasda',
      ee: {
        oi: 1000,
      },
    },
  },
}

let d = pickProps(ddd, ['name', 'addr.pp', 'addr.pp.ee'])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment