Search code examples
javascripttypescriptrecord

Setting up a record in typescript using keyof typeof


I've set up an object with my enum-like times of das as follows and I'm trying to make the correct type for a record based on these entries.

export const TIMEOFDAY = {
    FirstLight: 'First Light',
    Morning: 'Morning',
    Antemeridiem: 'Antemeridiem',
    Zenith: 'Zenith',
    Postmeridiem: 'Postmeridiem',
    Evening: 'Evening',
    LastLight: 'Last Light',
    Night: 'Night',
}

When I try to set up the record, it tells me that basically all the keys are missing in my record entries. It seems TS can't see that I'm referencing them via TIMEOFDAY.FirstLight as shown below.

type TimeOfDayData = {
    phase: number
    hours: number
    lux: number
    temperature: number
}

type TimeOfDayDataRecord = Record<keyof typeof TIMEOFDAY, TimeOfDayData>

const TIMEOFDAYDATA: TimeOfDayDataRecord = {
    [TIMEOFDAY.FirstLight]: /*   */ { phase: 1, temperature: 10, hours: 5, lux: 1 },
    [TIMEOFDAY.Morning]: /*      */ { phase: 2, temperature: 23, hours: 8, lux: 100 },
    [TIMEOFDAY.Antemeridiem]: /* */ { phase: 3, temperature: 42, hours: 13, lux: 300 },
    [TIMEOFDAY.Zenith]: /*       */ { phase: 4, temperature: 55, hours: 16, lux: 500 },
    [TIMEOFDAY.Postmeridiem]: /* */ { phase: 3, temperature: 48, hours: 22, lux: 300 },
    [TIMEOFDAY.Evening]: /*      */ { phase: 2, temperature: 32, hours: 25, lux: 100 },
    [TIMEOFDAY.LastLight]: /*    */ { phase: 1, temperature: 15, hours: 30, lux: 1 },
    [TIMEOFDAY.Night]: /*        */ { phase: 0, temperature: -10, hours: 33, lux: 0 },
}

I'm seeing the following error:

Type '{ [x: string]: { phase: number; temperature: number; hours: number; lux: number; }; }' is missing the following properties from type 'TimeOfDayDataRecord': Morning, Antemeridiem, Zenith, Postmeridiem, and 4 more.ts(2740)

Any ideas how to fix this or where I've made an error or wrong assumption?


Solution

  • Ok so based on your comments, you'll want

    type TimeOfDayDataRecord = Record<keyof typeof TIMEOFDAY, TimeOfDayData>
    

    Where the key for TimeOfDayDataRecord is set to a keyof typeof TIMEOFDAY ("a key from the type expressed from TIMEOFDAY")

    export const TIMEOFDAY = {
      FirstLight: 'First Light',
      Morning: 'Morning',
      Antemeridiem: 'Antemeridiem',
      Zenith: 'Zenith',
      Postmeridiem: 'Postmeridiem',
      Evening: 'Evening',
      LastLight: 'Last Light',
      Night: 'Night',
    }
    
    type TimeOfDayData = {
      phase: number
      hours: number
      lux: number
      temperature: number
    }
    
    
    type TimeOfDayDataRecord = Record<keyof typeof TIMEOFDAY, TimeOfDayData>
    
    const TIMEOFDAYDATA: TimeOfDayDataRecord = {
      "FirstLight": /*   */ { phase: 1, temperature: 10, hours: 5, lux: 1 },
      "Morning": /*      */ { phase: 2, temperature: 23, hours: 8, lux: 100 },
      "Antemeridiem": /* */ { phase: 3, temperature: 42, hours: 13, lux: 300 },
      "Zenith": /*       */ { phase: 4, temperature: 55, hours: 16, lux: 500 },
      "Postmeridiem": /* */ { phase: 3, temperature: 48, hours: 22, lux: 300 },
      "Evening": /*      */ { phase: 2, temperature: 32, hours: 25, lux: 100 },
      "LastLight": /*    */ { phase: 1, temperature: 15, hours: 30, lux: 1 },
      "Night": /*        */ { phase: 0, temperature: -10, hours: 33, lux: 0 },
    }
    /*
    
    The type created is:
    type TimeOfDayDataRecord = {
        Morning: TimeOfDayData;
        Antemeridiem: TimeOfDayData;
        Zenith: TimeOfDayData;
        Postmeridiem: TimeOfDayData;
        Evening: TimeOfDayData;
        Night: TimeOfDayData;
        FirstLight: TimeOfDayData;
        LastLight: TimeOfDayData;
    }
    
    And the Object created is:
    {
      "FirstLight": {
        "phase": 1,
        "temperature": 10,
        "hours": 5,
        "lux": 1
      },
      "Morning": {
        "phase": 2,
        "temperature": 23,
        "hours": 8,
        "lux": 100
      },
      "Antemeridiem": {
        "phase": 3,
        "temperature": 42,
        "hours": 13,
        "lux": 300
      },
      "Zenith": {
        "phase": 4,
        "temperature": 55,
        "hours": 16,
        "lux": 500
      },
      "Postmeridiem": {
        "phase": 3,
        "temperature": 48,
        "hours": 22,
        "lux": 300
      },
      "Evening": {
        "phase": 2,
        "temperature": 32,
        "hours": 25,
        "lux": 100
      },
      "LastLight": {
        "phase": 1,
        "temperature": 15,
        "hours": 30,
        "lux": 1
      },
      "Night": {
        "phase": 0,
        "temperature": -10,
        "hours": 33,
        "lux": 0
      }
    }
    */
    

    You also no longer need to use square brackets [] because you no longer need to compute the property.
    Missing any from (or added extra properties not already in) TIMEOFDAY will throw an error for TypeScript too which is handy