microsoft / microsoft/TypeScript

optional and readonly Filter Modifier for keyof

Open
#35,103 6 comments 9 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Awaiting More Feedback Suggestion
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue proposes new keyof modifier syntax for filtering optional, required, readonly, and editable properties, but names no repository files, tests, or entry points. Start by reviewing the existing keyof and mapped-type behavior; done would require an agreed syntax and semantics, implementation, and tests covering the suggested combinations.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.