Skip to content

Instantly share code, notes, and snippets.

@jspears
Last active August 15, 2022 19:03
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 jspears/ade9b962fab7ece3f79e96ce795fd1f9 to your computer and use it in GitHub Desktop.
Save jspears/ade9b962fab7ece3f79e96ce795fd1f9 to your computer and use it in GitHub Desktop.
NamedParameters from 'object'
// Tuplify code from:
//https://stackoverflow.com/questions/55127004/how-to-transform-union-type-to-tuple-type

// oh boy don't do this
type UnionToIntersection<U> =  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => (infer R) ? R : never

// TS4.1+
type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : [...TuplifyUnion<Exclude<T, L>>, L]


/**
 * Sometimes you want to be able to take named parameters,
 * and or 
 * 
 * Should put optional parameters last.
 */
type Never<T> = { [K in keyof T as T[K] extends never ? never : K extends 'prototype' ? never : K]: T[K] }

type WithRequiredKeys<T> = Never<{ [K in keyof T]-?: {} extends Pick<T, K> ? never : T[K] }>;
type WithOptionalKeys<T> = Never<{ [K in keyof T]-?: {} extends Pick<T, K> ? T[K] : never }>;
type NamedParameters_<T> = TuplifyUnion<T[keyof T]>

type NamedParameters<T> =[...NamedParameters_<WithRequiredKeys<T>>, ...NamedParameters_<WithOptionalKeys<T>>] | [T];

function example(...[hello, goodbye]:NamedParameters<{hello:string, goodbye:number}>){
    if (typeof hello === 'string'){
        console.log('its  a parameter', hello, goodbye);
    }else{
        console.log('its  an object', hello.hello, hello.goodbye);

    }
}
example({hello:'foo', goodbye:1});
example('foo', 1);

Playground Link

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