Skip to content

optional and readonly Filter Modifier for keyof #35103

Open
@1nVitr0

Description

@1nVitr0

Search Terms

  • keyof modifiers
  • only optional keys
  • only readonly keys
  • pick optional properties
  • pick required properties
  • pick readonly properties

Suggestion

Adding Support for modifiers to keyof could be very helpful. I'm picturing something like this

type Koptional = keyof? T;
type Kreadonly = readonly keyof T;

// Negations
type Krequired = keyof!? T;
type Keditable = !readonly keyof T;

// Combinations
type KrequiredReadonly = readonly keyof!? T;

The modifiers would act as "filters", only selecting the keys fitting the given modifiers.


As @jcalz pointed out, it might make more sense to use the existing + and - operators instead of the !.

Use Cases

This could be really useful for selecting properties of types based on them being optional / readonly. A possible use case for this would be the React defaultProps object (see example).

Of course this could negatively affect readability as especially Mapped Types can get fairly long

type PickEditableRequired<T> = {
    [P in !readonly keyof!? T]: T[P];
};

but I think it's still in the realms of comprehensibility.

Examples

type PickOptional<T> = {
    [P in keyof? T]-?: T[P];
};

type DrinkProps = {
    whoGetsUpAndMakesIt: string,
    type?: "water" | "coffee" | "coke" | "more coffee",
    vessel?: "cup" | "glass" | "HUGE cup",
    amount?: number
};

class Drink extends React.Component<Required<DrinkProps>> {
    public static defaultProps: PickOptional<DrinkProps> = {
        type: "water",
        vessel: "glass",
        amount: 250
    }

    render() {
        return <p>
            {this.props.whoGetsUpAndMakesIt} gets up and pours
            {this.props.amount}ml of {this.props.type} into a
            {this.props.vessel}.
        </p>
    }
}

Especially with many optional props the current method of

public static defaultProps: Pick<DrinkProps, "type" | "vessel" | "amount"> = { ... };

can get fairly tedious, especially as you have to add new optional props at 3 places (the type definition, the Pick UtilityType and in the defaultProps). The method using PickOptional and the ?-keyof-modifier reduces it to 2, and immediately notifies you if you declared a parameter optional, but haven't defined it in defaultProps.

This would also work without React in terms of default values:

type Order = {
    item: string,
    amount?: number,
    shipping?: "standard" | "express"
}
const defaultOrder: PickOptional<Order> = {
    amount: 1,
    shipping: "standard"
}

function placeOrder(order: Order): void {
    let data: Required<Order> = {...defaultOrder, ...order};
    console.log(`You ordered ${data.amount} ${data.item} with ${data.shipping} shipping.`);
}

I'm sure there are more (and better) use cases for this feature I can't think of right now...

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions