Tips for effectively typing an object with a variety of value types

Greetings and thank you for your help in advance.

I am currently working on creating a UI component that accepts boolean and string style props. However, I encountered an error related to the Styles type which includes the bg prop that accepts a string. I have tried different approaches to resolve this using a Record type, but it did not prove helpful as the issue arises at runtime.

The specific error points to

stylesProps[k as keyof StyleProps]
. What would be considered the best practice to tackle this error?

Furthermore, is there a more efficient method than using an array of keys for looping through expected key types? Currently, updating the code in two locations when adding more properties seems cumbersome, so I aim to streamline it into a single location.

"Type 'string | boolean | undefined' is not assignable to type 'undefined'.
  Type 'string' is not assignable to type 'undefined'.ts(2322)"
// .tsx
// styles props
const keys = ["block", "center", "row", "column", "border", "bg"];

type Styles = {
  block: boolean;
  center: boolean;
  row: boolean;
  column: boolean;
  border: boolean;
  bg: string;
};

type AllowedStyles = Partial<Styles>;

// component props
type Props = Partial<
  AllowedStyles & { children: JSXElement | JSXElement[] | undefined }
>;

// utilities
// this function will take in component props and return an object containing just the [k,v] of style props
const getBoxStyleProps = (props: Props): AllowedStyles => {
  let stylesProps: AllowedStyles = {};

  for (let k of keys) {
    stylesProps[k as keyof AllowedStyles] = props[k as keyof AllowedStyles];
//  ^-----------------------------------^ TS err
  }

  return stylesProps;
};

// more code, not included
//.jsx using component here with allowed style props
export default function Index() {
  return (
    <Box block column border bg="blue">
    </Box>
  );
}

Answer №1

By utilizing Object.fromEntries and Object.entries, it is possible to filter out specific keys:

const getBoxStyleProps = (props: Props): AllowedStyles => {
  let stylesProps: AllowedStyles = Object.fromEntries(Object.entries(props).filter(([key]) => keys.includes(key)));

  return stylesProps;
};

Playground


Note: this approach is less strict in terms of typing


You can also make things more advanced using a generic function:

const getBoxStyleProps = <K extends keyof Styles>(props: Props, keys: K[]): { [P in K]: Styles[P] } => {
  let stylesProps = Object.fromEntries(Object.entries(props).filter(([key]) => keys.includes(key as K)));

  return stylesProps as { [P in K]: Styles[P] } ;
};

const v = getBoxStyleProps(props, ["block", "center"]);
//    ^? { block: boolean; center: boolean }

Playground

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

What is the best way to dismiss a Bootstrap modal with a form inside after submitting the form?

Within a Bootstrap modal, I have a form and I want to automatically close the modal when the user clicks the submit button. Here's the code snippet: export class AddPartModalComponent implements OnInit { @Input() id:number; closeResult: string ...

"Utilizing Typescript and React to set a property's value based on another prop: A step-by

Is there a way to create a dynamic prop type in React? I have an Alert component with various actions, such as clicking on different components like Button or Link. I am looking for a solution like this: <Alert actions={[{ component: Link, props: { /* ...

Filtering formArray controls in Angular based on a condition

I'm currently dealing with an issue where I need to filter formArray controls public checklistForm!: FormGroup; this.checklistForm = this.fb.group({ checklistItems: this.fb.array([]) }); // some logic public checklistItems(): FormArray { ...

Determining User Existence in AWS DynamoDB with Node.js Before Creating New Record

Currently, I am in the process of developing an AWS Lambda function to create a new customer (lead). However, prior to the creation of the customer, there is a need to perform a check to determine if the user already exists. The identification of a custome ...

What is the reason behind having to press the Tab button twice for it to work?

Currently, I am implementing a Tabbed Form with jQuery Functionality in Angular 4. The Tabbed Form itself is functioning, but I've noticed that I have to click the Tab Button twice for it to respond. See the code snippet below: TS declare var jquery ...

Creating a tsconfig.json file that aligns perfectly with your package.json and tsc command: a step-by-step

I've chosen to use TodoMvc Typescript-Angular as the starting point for my AngularJS project. Everything is working smoothly so far. Here's a breakdown of what I can do: To manage all dependencies, I simply run npm install or npm update based o ...

Combining files/namespaces/modules in Typescript: How to do it?

Even though I believe the solution may be simple, understanding how to merge enums across multiple files is eluding me when reading through the documentation. // a.ts enum Color{ RED, BLUE } // b.ts enum Day{ MONDAY, TUESDAY } // c ...

Testing React-Redux Containers with JestIs this okay or would

Embarking on my journey in React with Redux, I am currently working on creating a TestUnit for a container that links to a dialog responsible for rendering a table. Within the container, I have: a mapStateToProps constant which provides properties for t ...

Unexpected file directories being included in Webpack

My project consists of two webpack configurations that target different components within the directory structure below: ./scripts/react/TestA.tsx ./scripts/typescript/TestB.tsx Although there are no explicit imports between these components, running the ...

Retrieve the property values of `T` using a string key through the `in

Having trouble accessing a property in an object using a string index, where the interface is defined with in keyof. Consider the following code snippet: interface IFilm { name: string; author: string; } type IExtra<T extends {}> = { [i ...

Learn the method for triggering events with a strongly-typed payload in Vue 3 Composition API and TypeScript

I'm currently exploring Vue 3 Composition API along with TypeScript, particularly focusing on emitting events with a strictly typed payload. There's an example provided below, but I'm unsure if it's the most effective way to achieve t ...

HTML code for adding a dropdown menu inside a table cell

I am trying to set up a table where one cell functions as a dropdown menu. The data.field is being fetched from the backend and I want it to be displayed during rendering. Additionally, a fList is also retrieved from the backend. When a user clicks on th ...

Using Angular 2 to invoke a component

Currently, I am working on building a new Angular 2 application. Within the home.component.ts file, there is a small form that has been designed as shown in the image linked below https://i.sstatic.net/nimDm.jpg After the user clicks on the Submit button ...

Ways to simulate a variable imported in the module being tested without it being a function parameter can be achieved by using describe.each and changing the mock value for each test

I have a requirement to test a function within my TypeScript module. module-to-test.ts import { config } from './app-config'; export const isSomethingWhatINeedSelector = createSelector( firstDependencySelector, secondDependencySelector ...

Team members

Just started diving into Angular and practicing coding with it while following video tutorials. However, I've stumbled upon something in my code that has left me puzzled. I'm curious about the significance of the line "employees: Employee[]" in ...

'Mastering the implementation of promises in React context using TypeScript'

I've been diving into the world of incorporating TypeScript in React and I'm facing a challenge with implementing async functions on context. The error that's popping up reads as follows: Argument of type '{ userData: null; favoriteCoc ...

One effective way to transfer state to a child component using function-based React

My goal is to pass an uploaded file to a child component in React. Both the parent and child components are function-based and utilize TypeScript and Material-UI. In the Parent component: import React from 'react'; import Child from './ ...

Is there a way in Typescript to determine the type of a union type when a specific condition is satisfied?

I am faced with a scenario where I have an object that can take on two different shapes: {ageTop:42} or {locations: [{name:Myrtle Beach}]} These objects are passed as parameters to a function, and I want to ensure that the function only receives the t ...

Perform the subtraction operation on two boolean values using Typescript

I'm working with an array: main = [{ data: x, numberField: 1; }, { data: y, numberField: 2; }, { data: x, numberField: 3; }, { data: z, numberField: 4; }, { data: ...

How to make Angular2 page fill the entire screen height

I'm trying to make a div take up the full screen in an angular2 template Here's what I've attempted so far: <div class="auth-container"> </div> In the CSS file: .auth-container{ height: 100%; //also tried with min-height ...