Skip to content

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented Dec 10, 2016

With this PR we more consistently propagate property modifiers in mapped types. For a given type parameter T, mapped types declared as { [P in keyof T]: X } or { [P in K]: X}, where K is a type parameter K extends keyof T, now propagate property modifiers from T. This in particular means that the predefined type Pick<T, K> now propagates property modifiers from T.

The intuitive way to think of this is that when a mapped type is known to operate on property names from a particular type (i.e. T in keyof T) or a subset of the property names of a particular type, then we propagate the property modifiers from that type.

interface Foo {
    a: string;
    b?: number;
}

function setState<T, K extends keyof T>(obj: T, props: Pick<T, K>) {
    for (let k in props) {
        obj[k] = props[k];
    }
}

let foo: Foo = { a: "hello", b: 42 };
setState(foo, { a: "test", b: 43 })
setState(foo, { a: "hi" });
setState(foo, { b: undefined });
setState(foo, { });
setState(foo, foo);
setState(foo, { a: undefined });  // Error
setState(foo, { c: true });  // Error

class C<T> {
    state: T;
    setState<K extends keyof T>(props: Pick<T, K>) {
        for (let k in props) {
            this.state[k] = props[k];
        }
    }
}

let c = new C<Foo>();
c.setState({ a: "test", b: 43 });
c.setState({ a: "hi" });
c.setState({ b: undefined });
c.setState({ });
c.setState(foo);
c.setState({ a: undefined });  // Error
c.setState({ c: true });  // Error

Note that because Pick<T, K> now propagates modifiers, it can no longer be used to "strip" modifiers.

Fixes #12793.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants