WBT
WBT

Reputation: 2485

How do I assign to a variable-specified key of a `Partial<MyInterface>` without an error that it can't be assigned to undefined?

In this TypeScript code, also repeated below, there is a function which builds up a partial object in the application's type system from component parts. However, it doesn't work with the noted error that all the result's properties are undefined in a way that prevents assigning anything else to them.

This is a simplified refactor of this question meant to avoid having the simplifying refactor invalidate any points of an answer posted there; you can see more of what was previously attempted in that description.

How do I get rid of this error while still dynamically building up an object?


The code at the Playground link is:

interface HornPlayer {instrumentName: 'saxophone' | 'clarinet' | 'trumpet';}
interface ChordPlayer {instrumentName: 'piano' | 'organ' | 'vibraphone';}
interface BassPlayer {instrumentName: 'double bass' | 'tuba' | 'bass guitar';}
interface DrumPlayer {kitItemCount: number;}
type Instrumentalist = HornPlayer | ChordPlayer | BassPlayer | DrumPlayer;
interface JazzQuartet {
    horn: HornPlayer,
    chords: ChordPlayer,
    bass: BassPlayer,
    drums: DrumPlayer
}
declare function recruit<R extends keyof JazzQuartet>(roleToRecruitFor: R) : JazzQuartet[R];
const demoFn = function (
    //Note: If roles are repeated here it's OK; 
    //the last recruit for a repeated role will be in the combo.
    rolesToInclude : (keyof JazzQuartet)[],
) : Partial<JazzQuartet> {
    let combo : Partial<JazzQuartet> = {};
    for(let role of rolesToInclude) {
        //Error ts(2322): Type 'HornPlayer | ChordPlayer | BassPlayer | DrumPlayer'
        //is not assignable to type 'undefined'.
        combo[role] = recruit(role);
    }
    return combo;
}

Upvotes: 1

Views: 47

Answers (1)

Parzh from Ukraine
Parzh from Ukraine

Reputation: 9903

Try to use Pick<object, key> type instead of Partial<object>. This would require having a type parameter for the key, a.k.a. the "role" in the jazz quartet:

interface JazzQuartet {
    horn: {
        instrumentName: 'saxophone' | 'clarinet' | 'trumpet'
    }
    chords: {
        instrumentName: 'piano' | 'organ' | 'vibraphone'
    },
    bass: {
        instrumentName: 'double bass' | 'tuba' | 'bass guitar'
    },
    drums: {
        kitItemCount: number
    }
}

declare function recruit<R extends keyof JazzQuartet>(roleToRecruitFor: R) : JazzQuartet[R];

function combine<Role extends keyof JazzQuartet>(roles: Role[]): Pick<JazzQuartet, Role> {
    const combo = {} as Pick<JazzQuartet, Role>

    for (const role of roles) {
        combo[role] = recruit(role)
    }

    return combo
}

Try it.

Upvotes: 1

Related Questions