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

Add second type parameter to Partial<T>, Required<T>, and Readonly<T> to selectively modify properties #35703

Closed
5 tasks done
1000hz opened this issue Dec 16, 2019 · 3 comments
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript

Comments

@1000hz
Copy link

1000hz commented Dec 16, 2019

Search Terms

Partial Required Readonly mapped types

Suggestion

Currently Partial<T> Required<T> and Readonly<T> apply their modifications wholesale to all properties of T, but oftentimes this is more than what you intend. We should consider adding a second type parameter to limit the properties affected by the modifier.

type Partial<T, K extends keyof T = keyof T> = Omit<T, K> & {
    [P in K]?: T[P];
};

type Required<T, K extends keyof T = keyof T> = Omit<T, K> & {
    [P in K]-?: T[P];
};

type Readonly<T, K extends keyof T = keyof T> = Omit<T, K> & {
    readonly [P in K]: T[P];
};

Use Cases

Oftentimes it's necessary to make only a few or single property optional or required. This currently requires a lot of manual type intersection, as one needs to split the type apart, apply the mapped type on this subset, and reconstruct the full type. It would be much simpler if we moved this into these predefined mapped types to make them more powerful.

Examples

type T = {
    foo: string;
    bar: string;
    baz?: string;
}

/**
 * foo+?: string | undefined;
 * bar+?: string | undefined;
 * baz?: string | undefined;
 */
const pt: Partial<T> = {} // Backwards compatible


/**
 * foo+?: string | undefined;
 * bar: string;
 * baz?: string | undefined;
 */
const ptfoo: Partial<T, "foo"> = {
    bar: "bar"
}


/**
 * foo+?: string | undefined;
 * bar+?: string | undefined;
 * baz-?: string;
 */
const ptrbaz: Required<Partial<T>, "baz"> = {
    baz: "baz"
}

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.
@jcalz
Copy link
Contributor

jcalz commented Dec 16, 2019

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code

But what about this? Currently:

function foo<T>() {
    const z: Partial<T> = {} // okay
}

With proposed change:

function foo<T>() {
    const z: Partial<T> = {} // error!
    // ┌> ~ 
    // Type '{}' is not assignable to type 'Pick<T, Exclude<keyof T, keyof T>>
}

Playground link

I wouldn't advise altering predefined utility types unless there is a bug in them, since doing so changes other people's existing code and the best case scenario is that they won't notice.

@dragomirtitian
Copy link
Contributor

I also worry about adding more complexity to the built-in types, it might make them harder to understand for beginners.

@RyanCavanaugh RyanCavanaugh added Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript labels Dec 18, 2019
@RyanCavanaugh
Copy link
Member

Changing these types is a guaranteed breaking change.

You can write these forms yourself if that's what you'd like to have; after the feedback from #30455 that we added the "wrong" Omit type we're completely uninterested in adding new built-in types where we have to make any semantic stylistic decisions unless it's absolutely necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants