Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement pick & omit functionality #943

Open
aspirisen opened this issue Jan 29, 2024 · 6 comments
Open

Implement pick & omit functionality #943

aspirisen opened this issue Jan 29, 2024 · 6 comments
Assignees
Labels
question Further information is requested

Comments

@aspirisen
Copy link

Feature Request

A description of the problem you're trying to solve.

TypeScript allows you to combine several types into one, however, sometimes you need to extract or omit special subset of fields from that "combined" object. I face the necessity of pick/omit when I work with React because React is unhappy when you pass non-dom properties to jsx, but I think that functions will be useful in other cases too.

interface LayoutStyles {
    display?: 'block' | 'flex'
    width?: number
    height?: number
    // many other fields
}

interface SpacingStyles {
    padding?: string
    margin?: string
    // many other fields
}

interface Props extends LayoutStyles, SpacingStyles, ButtonHTMLAttributes<HTMLButtonElement> {}

function Component(props: PropsWithChildren<Props>) {
    return (
        // Along with button html props we pass some attributes that doesn't exist in html lang
        // Moreover, we accidentally pass width and height attributes which exist in html 
        // and hence they will be added in the final markup, but it is not what we want
        <button
            {...props}
            style={{ display: props.display, width: props.width, height: props.height, padding: props.padding, margin: props.margin }}
        >
            {props.children}
        </button>
    )
}

An overview of the suggested solution.

Typia could have the following functions:
pick - takes generic of what fields should be picked and the source object. It returns new object with picked fields from the generic.
omit - takes generic of what fields should be omitted and the source object. It returns new object without fields from the generic.
extract - takes generic of what fields should be extracted and the source object. It returns a tuple with two objects - the extracted fields and the rest fields. As you can see the pick and omit functionality can be achieved via the extract function, but I think to worth to leave all of them just for the purpose of simplicity and performance.

Along with other functions from Typia there can be functions like createPick, createOmit and createExtract.

Examples of how the suggestion would work in various places.

function Component(props: PropsWithChildren<Props>) {
    return (
        <button
            {...typia.misc.omit<LayoutStyles & SpacingStyles>(props)}
            style={typia.misc.pick<LayoutStyles & SpacingStyles>(props)}
        >
            {props.children}
        </button>
    )
}

or

function Component(props: PropsWithChildren<Props>) {
    const [style, rest] = typia.misc.extract<LayoutStyles & SpacingStyles>(props)

    return (
        <button {...rest} style={style}>
            {props.children}
        </button>
    )
}

Note about deep functionality - probably there will be cases when you want to deeply pick or omit object, but that feels much more complicated and I think it is worth to leave it for further improvements.

@samchon
Copy link
Owner

samchon commented Jan 29, 2024

Is this feature what you want?

https://typia.io/docs/misc/#clone-functions

@samchon samchon self-assigned this Jan 29, 2024
@samchon samchon added the question Further information is requested label Jan 29, 2024
@aspirisen
Copy link
Author

@samchon as I understand clone makes the same as pick. However, I am not sure that it can do omit.

@samchon
Copy link
Owner

samchon commented Jan 31, 2024

Clone with Omit<T, K> type like below may what you want.

typia.misc.assertClone<Omit<T, "a"|"b">>(input);

@aspirisen
Copy link
Author

aspirisen commented Mar 27, 2024

@samchon it is not exactly as omit, it doesn't return rest properties.

For example

interface Test {
  a?: string;
  b?: string
}

const data: Record<string, any> = { c: 'a' }
const other = typia.misc.omit<Test>(data)

Using typia.misc.assertClone<Omit<Test, keyof Test>>(data); looks like does nothing

ps. looks like clone skips function properties, what also is not the same as pick

const $co0 = (input)=>({
          onPress: "function" === typeof input.onPress ? undefined : input.onPress
      });
  return "object" === typeof input && null !== input ? $co0(input) : input;

@samchon samchon closed this as not planned Won't fix, can't repro, duplicate, stale Jun 12, 2024
@samchon
Copy link
Owner

samchon commented Jun 12, 2024

If still want this feature, can you write the function interface?

@samchon samchon reopened this Jun 12, 2024
@AlexRMU
Copy link
Contributor

AlexRMU commented Aug 7, 2024

I think he's talking about something similar:
#202
lodash/lodash#3172

type T1 = {
    a: string;
};
type T2 = {
    b: string;
};
const obj: T1 & T2 = {
    a: "",
    b: "",
};
const { target, rest } = fn<T1>(obj);
// target is T1 - { a: "" }
// rest is T2 - { b: "" }

This cannot be done now due to TS limitations:
https://stackoverflow.com/questions/76490186/use-type-parameters-with-exact-type-instead-of-extending

Therefore, the prune function (and similar functions) can change the shape of an object without changing its type:
playground (#1205)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants