Skip to content

Object values are not assignable when wrapped in a Partial #26266

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

Closed
rraval opened this issue Aug 7, 2018 · 3 comments
Closed

Object values are not assignable when wrapped in a Partial #26266

rraval opened this issue Aug 7, 2018 · 3 comments
Assignees
Labels
Bug A bug in TypeScript Domain: Mapped Types The issue relates to mapped types Fixed A PR has been merged for this issue

Comments

@rraval
Copy link

rraval commented Aug 7, 2018

TypeScript Version: Version 3.1.0-dev.20180807

Search Terms: keyof mapped partial

Code

Compiled with --strictNullChecks:

interface Value<T> {
    value: T;
}

interface Builder<T> {
    buildValue(): Value<T>;
}

type BuilderMap<Keys extends PropertyKey> = {
    [K in Keys]: Builder<any>;
}

type ValueMap<Keys extends PropertyKey> = {
    [K in Keys]: Value<any>;
};

function makeFooMap<Map extends BuilderMap<"foo">>(builderMap: Map) {
    const valueMap: Partial<ValueMap<keyof Map>> = {};
    valueMap["foo"] = builderMap["foo"].buildValue();
}

Expected behavior:

The code compiles without errors.

Actual behavior:

The compiler dislikes the valueMap["foo"] assignment:

bug.ts:19:5 - error TS2322: Type 'Value<any>' is not assignable to type 'ValueMap<keyof Map>["foo"]'.

19     valueMap["foo"] = builderMap["foo"].buildValue();
       ~~~~~~~~~~~~~~~

Tested versions:

  • 2.9.2: no error
  • 3.0.1: reports error
  • 3.1.0-dev.20180807: reports error

Changing the code to remove the Partial and using a type assertion seems to work:

function makeFooMap<Map extends BuilderMap<"foo">>(builderMap: Map) {
    const valueMap: ValueMap<keyof Map> = {} as ValueMap<keyof Map>;
    valueMap["foo"] = builderMap["foo"].buildValue(); // no error anymore
}

Getting rid of the keyof and explicitly providing a list of keys also works:

function makeFooMap<Map extends BuilderMap<"foo">>(builderMap: Map) {
    const valueMap: Partial<ValueMap<"foo">> = {};
    valueMap["foo"] = builderMap["foo"].buildValue(); // no error anymore
}

Playground Link: Playground Link

Related Issues: #25010 maybe?

@ghost
Copy link

ghost commented Aug 7, 2018

interface Value { x: number };

type Values<Keys extends PropertyKey> = { [K in Keys]: Value; }

function f0<T extends { "foo": number }>(_: T, value: Value): Partial<Values<keyof T>> {
    const valueMap: Partial<Values<keyof T>> = {};
    const x: Value | undefined = valueMap["foo"]; // No error
    valueMap["foo"] = value; // Error?
    return valueMap;
}

function f1<K extends string>(x: Values<K>): Partial<Values<K>> {
    return x; // Error?
}

No error if using type Value = number;. No error if you remove extends { "foo": number }.
I would expect Value to be assignable to valueMap["foo"] which is of type Value | undefined (regardless of the type of keyof T).
I would also expect Values<K> to be assignable to Partial<Values<K>> regardless of the value of K.

@ghost ghost added Bug A bug in TypeScript Domain: Mapped Types The issue relates to mapped types labels Aug 7, 2018
@rraval
Copy link
Author

rraval commented Aug 7, 2018

@Andy-MS I'm not sure if this is related or if this should be a separate bug report, but I'm seeing some weird behaviour with Pick as well:

type Values<Keys extends PropertyKey> = {
    [K in Keys]: number;
};

function f0<Keys extends PropertyKey>(attrs: Values<Keys>) {
    for (const key in attrs) {
        const value: number = attrs[key]; // No error
    }
}

function f1<Keys extends PropertyKey>(attrs: Pick<Values<Keys>, Keys>) {
    for (const key in attrs) {
        const value: number = attrs[key]; // Error
    }
}

The error in question is:

bug.ts:13:15 - error TS2322: Type 'Values<Keys>[Extract<Keys, string>]' is not assignable to type 'number'.

13         const value: number = attrs[key]; // Error
                 ~~~~~

In my head, wrapping an object in Pick shouldn't affect my ability to read out values from the object, but that may just be my mistaken understanding.

@ahejlsberg
Copy link
Member

This was fixed by #26698. All of the above examples now type check with no errors.

@ahejlsberg ahejlsberg added the Fixed A PR has been merged for this issue label Aug 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: Mapped Types The issue relates to mapped types Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

3 participants