Creating a TypeScript record with the help of the keyof operator and the typeof keyword

I have an object set up with my enum-like times of day and I am attempting to create 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 trying to define the record, it is indicating that all keys are missing in the record entries. TypeScript seems unable to recognize that I am referencing them using 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 },
}

The error message displayed is:

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 suggestions on how to resolve this issue or where the mistake may lie?

Answer №1

After considering your feedback, here's the modified code:

type TimeOfDayDataRecord = Record<keyof typeof TIMEOFDAY, TimeOfDayData>

In this snippet, the key for TimeOfDayDataRecord is assigned to keyof typeof TIMEOFDAY (which means "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 declaration for TimeOfDayDataRecord now looks like this:
type TimeOfDayDataRecord = {
    Morning: TimeOfDayData;
    Antemeridiem: TimeOfDayData;
    Zenith: TimeOfDayData;
    Postmeridiem: TimeOfDayData;
    Evening: TimeOfDayData;
    Night: TimeOfDayData;
    FirstLight: TimeOfDayData;
    LastLight: TimeOfDayData;
}

And the Object created is as follows:
{
  "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
  }
}
*/

No need for square brackets [] anymore since property computation is unnecessary.
Any missing or additional properties in TIMEOFDAY will trigger a TypeScript error alerting you promptly.

Answer №2

You're almost at the finish line, but here's a slight twist.

type identifier = keyof typeof TIMEOFDAY;

In this snippet, the variable identifier represents keys from TIMEOFDAY. However, what you really need are the values associated with those keys within TIMEOFDAY.

To achieve this, bracket notation comes to the rescue easily.

type value = typeof TIMEOFDAY[keyof typeof TIMEOFDAY]

The entire code block should function as illustrated below:

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<typeof TIMEOFDAY[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 },
}

Link

Answer №3

You seem to have two issues here. Firstly, your keys must exactly match the strings in your enum-like object, so ensure there are no spaces in "Last Light" and "First Light."

The second problem is that TypeScript inherits the type of

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

as something like:

const TIMEOFDAY: {
    FirstLight: string;
    Morning: string;
    Antemeridiem: string;
    Zenith: string;
    Postmeridiem: string;
    Evening: string;
    LastLight: string;
    Night: string;
}

This means it doesn't match the key type either. To fix this, consider using as const which makes it readonly.

type TimeOfDayData = {
    phase: number
    hours: number
    lux: number
    temperature: number
}
export const TIMEOFDAY = {
    FirstLight: 'FirstLight',
    Morning: 'Morning',
    Antemeridiem: 'Antemeridiem',
    Zenith: 'Zenith',
    Postmeridiem: 'Postmeridiem',
    Evening: 'Evening',
    LastLight: 'LastLight',
    Night: 'Night',
} as const

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 },
}

Check out a working example here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React failing to acknowledge Styled Components

Here is an example of a CustomHandle Styled component that extends Handle and HandleProps from the 'reactflow' library: interface CustomHandleProps extends HandleProps { istarget?: boolean; zoomedout?: boolean; placement: number; placemen ...

Encountering a problem with file upload in AngularJs

I am encountering an issue with my simple file upload code. The error message is being displayed as follows: https://i.sstatic.net/NAPYH.png Below is the code snippet causing the problem: <input type="file" name="student_image" onchange="angular.elem ...

What is the best way to ensure that an ASync function only continues once all necessary information has been collected?

retrieveStudentGrades() { let grades = {}; let totalStudents = this.state.studentDetails.length; let studentCount = 0; this.state.courses.map((course) => { this.state.studentDetails.map((student) => { request.get( ...

VueJS: Send all unspecified attributes to child component in the same way as using v-bind="$props"

I am looking for a way to receive any props passed by the parent component into the child component without explicitly mentioning them in props:[]. This is because I may not always know which props will be bound. Parent component <template> <di ...

Maximizing Server Performance with Query Data Caching

I am currently developing an Express app that involves transferring data from views to a database. However, the majority of the data needs to be linked to other data within different tables in the database. For instance, there is a "choose student name" d ...

I'm receiving an undefined output, does anyone have any suggestions to fix this?

let userInput = prompt("Please input a month number"); let monthName; switch(userInput) { case 1: monthName = "January"; break; case 4: monthName = "April"; break; case 8: m ...

Exploring practical scenarios and application of the Repository pattern in node.js

Could anyone provide an example of how to use this pattern and explain its purpose? I am a bit confused about the database instance and where it can be located. Do I have the freedom to manipulate it in any way? Am I mistaken? ...

Is the token in localStorage valid? Here's how to find out!

Currently, I am integrating my ReactJS frontend with a PHP backend system. When a user logs in, the JWT Token is stored in the localStorage. I have certain static react pages that should only be accessible when a user is logged in, so I have enclosed the ...

Adjust the URL dynamically depending on the class in PHP

Something unique has come up with one of my clients - they want to switch the primary logo when scrolling down the page. Initially, the top logo should be displayed, then as the user scrolls, a second logo should take its place. To achieve this effect, I ...

Placing a three.js object in an array at a specific position

My goal is to move my object along the x-axis by 1 every time my animate function is called. However, I keep encountering an error that says "cannot read property x of undefined." To address this issue, I started adding each mesh I create to the sceneObje ...

What is the most effective way to compress a paragraph and fill in the remainder with '...'?

Here is some content wrapped in a paragraph, see below: <div style="width:30px"> <p>12345678901234567890abcdefghijklmnopqrstuvwxyzIlovePaulinaVega</p> </div> We are aware that this content will be displayed on multiple lines due ...

React - CSS Transition resembling a flip of a book page

As I delve into more advanced topics in my journey of learning React and Front Web Dev, I discovered the ReactCSSTransitionGroup but learned that it is no longer maintained so we now use CSSTransitionGroup. I decided to create a small side project to expe ...

Button addition in Angular is malfunctioning

I have a form with add and remove fields implemented using angularjs. It works fine when running outside the div, but when placed inside a div, only the remove function is working. Can you please advise on what might be going wrong? <body> <div ...

Arrange Angular code in WebStorm by placing decorated variables after non-decorated ones

I am currently working on configuring arrangement rules for organizing class local variables before input variables. I want to structure them like this: private x; public y; @Input private z; @Input public q; However, despite my efforts, I have been unab ...

The ng-controller directive fails to function on the content of Kendo tabstrip tabs

My ng-controller is not functioning properly for the kendo tabstrip tab content. Could you please review my code below? <!--tabstripCtrl.js--> angular.module('tabstripApp',[]); var app = angular.module('tabstripApp'); app.con ...

Exploring the use of the caret symbol (^) for exponentiation

I am embarking on a project to develop an uncomplicated graphing calculator that enables users to input a function of f (such as f(x) = x^2+2x+6). Essentially, the JavaScript code should replace the x in the function with a specific number and then compute ...

Employing jQuery to extract the text from the h4 class="ng-binding" element beyond the Angular scope

Is it possible to retrieve the current text content of <h4 class="ng-binding"></h4>? The text content is generated dynamically within the angular.js setup. I am interested in finding a way to extract this text using jQuery or JavaScript from ...

Is it possible to interchange the positions of two components in a routing system?

driver-details.component.ts @Component({ selector: 'app-driver-details', templateUrl: './driver-details.component.html', styleUrls: ['./driver-details.component.css'] }) export class DriverDetailsComponent implements OnI ...

Leveraging anonymous functions within an IF statement in JavaScript

Can you explain how to implement an anonymous function within an if statement? Feel free to use the provided example. Thank you if(function(){return false;} || false) {alert('true');} For more information, visit https://jsfiddle.net/san22xhp/ ...

When the button with an image is clicked, it will display a loading element

I have developed an application that heavily utilizes ajax, and I am looking to implement the following functionality: I would like to have a button with both text and an image. When this button is clicked, it should be disabled, and instead of the origina ...