Can data be filtered based on type definitions using Runtime APIs and TypeDefs?

My theory: Is it feasible to generate a guard from TypeDefs that will be present at runtime? I recall hearing that this is achievable with TS4+.

Essentially, two issues; one potentially resolvable:

  1. If your API (which you can't control) provides noisy data and you need to filter them based on existing type definitions, what approach would you take?

  2. At times, your type definitions may appear unconventional, making it challenging to filter by lodash.keyBy as the iteratee could vary in shape depending on the given TypeDefs.

For instance:

You have an object type defined as follows:

type ObjectType = {
  [key: string]: {
    foo?: string | number;
  };
};

The following data would pass based on the above ObjectType:

const someOKCollection: Array<ObjectType> = [
  { june: { foo: 1 } },
  { earth: {} },
  { milky: { foo: "Hi" } }
];

Imagine this data is received from an API:

const collectionFromApi: Array<unknown> = [
  { car: { foo: 1 } },
  { soup: {} },
  { water: { foo: "Hi" } },
  { sun: { bar: "Hi" } }
];

In this scenario, the entry for sun is unnecessary due to the ObjectType (as it contains bar). The challenge lies in transforming the data into:

const desiredResult = {
  noMatter: { foo: 1 },
  what: {},
  Ever: { foo: "Hi" }
};

Main Question:

Ignoring the solvability of the first question, how should the iteratee be automatically crafted from the TypeDefinition so that utilizing lodash.keyBy or other collection functions results in the desired outcome?

UPDATE: Explore a simplified CodeSandBox here: https://codesandbox.io/s/typescript-lodash-types-6844w0?file=/src/index.type.ts (please note: root key names may differ at runtime; only TypeDefs must be adhered to)

Answer №1

When not using lodash:

Check out this example on CodeSandbox

// import keyBy from "lodash/fp/keyBy";

type ObjectType = {
  [key: string]: {
    foo?: string | number;
  };
};

// const someOKCollection: Array<ObjectType> = [
//   { a: { foo: 1 } },
//   { b: {} },
//   { c: { foo: "Hi" } }
// ];

const collectionFromApi: unknown[] = [
  { a: { foo: 1 } },
  { b: {} },
  { c: { foo: "Hi" } },
  { d: { bar: "Hi" } }
];

type AllowedKey = "a" | "b" | "c";
const allowedKeys = new Set<AllowedKey>(["a", "b", "c"]);

// const desiredResult = {
//   a: { foo: 1 },
//   b: {},
//   c: { foo: "Hi" }
// };

type Result = {
  [key in AllowedKey]: { foo?: string | number };
};

const y = collectionFromApi.reduce<Result>((acc, val) => {
  if (typeof val !== "object" || val === null) return acc;

  const key = Object.keys(val)[0];

  if (
    key === undefined ||
    !allowedKeys.has(key as AllowedKey)
  ) {
    return acc;
  }

  acc[key as AllowedKey] = (val as Result)[key as AllowedKey];
  return acc;

}, {} as Result);
console.log("Y", y);

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

When working on styling a different Styled Component, how should one define the type of props required?

I'm currently working on a NextJS project using styled components and typescript. I have customized a div element like this: export const ClippedOverlay = styled( ( props: React.DetailedHTMLProps< React.HTMLAttributes<HTMLDivElement& ...

webpack - compile one TypeScript file separately (2 actions)

In summary... When my Vue files are combined with background.ts, webpack processes them to create bundled vue files along with background.js I'm unable to run the background.js script I expected background.js to only contain "console.log(' ...

What could be the reason for my Angular 2 app initializing twice?

Can someone help me figure out why my app is running the AppComponent code twice? I have a total of 5 files: main.ts: import { bootstrap } from '@angular/platform-browser-dynamic'; import { enableProdMode } from '@angular/core'; impor ...

What is the method in TypeScript for defining a property in an interface based on the keys of another property that has an unknown structure?

I recently utilized a module that had the capability to perform a certain task function print(obj, key) { console.log(obj[key]) } print({'test': 'content'}, '/* vs code will show code recommendation when typing */') I am e ...

Using Typescript for testing React components: successfully passing an array of objects as props

My current approach involves passing an array of objects to mock component data for testing: const mockPackage = { id: '1232-1234-12321-12321', name: 'Mock Package', price: 8.32, description: 'Mock description', glo ...

What is the reason for TypeScript not throwing an error when an interface is not implemented correctly?

In my current scenario, I have a class that implements an interface. Surprisingly, the TypeScript compiler does not throw an error if the class fails to include the required method specified by the interface; instead, it executes with an error. Is there a ...

Challenges encountered when assigning values in a form with Material UI, Formik, and Typescript

When attempting to set the 'role' and 'active' values on a form, I encountered a couple of issues. The first problem arises from the fact that the selectors' original values are not being properly set. These values are fetched in ...

Z-order for ClockPicker

Within my application, I've implemented a pop-up for inputting event data. One of the fields within this pop-up is for setting the time using the DateTimePicker from MUI. <Popup width={600} height={600} ...

Issue with ngClass not updating during Route Event

I am using a bottomNavigation component that changes its style to indicate which route we are currently on. Below is the template for the bottom-navigation: class="menu-icon" [ngClass]="{ 'active-item': buttonActivated.value == '/my-goa ...

When I define a type in TypeScript, it displays "any" instead

Imagine a scenario where we have a basic abstract class that represents a piece in a board game such as chess or checkers. export abstract class Piece<Tags, Move, Position = Vector2> { public constructor(public position: Position, public tags = nul ...

Using TypeScript to implement Angular Draggable functionality within an ng-template

Sorry if this question has been asked before, but I couldn't find any information. I am trying to create a Bootstrap Modal popup with a form inside and I want it to be draggable. I have tried using a simple button to display an ng-template on click, b ...

Using checkboxes for filtering in a React application

Here are the data sets I am working with: const dataSet = [ { id: 1, title: 'object1', published: true, }, { id: 2, title: 'object2', published: true, }, { id: 3, title: 'object3', ...

Trigger on the cancellation or completion of a nested observable

I'm seeking a way to detect if an inner observable was not successfully completed (due to everyone unsubscribing) and then emit a value in that scenario. Something akin to defaultIfEmpty, but the current solution isn't effective. A trigger exis ...

Creating a type-safe method wrapper in TypeScript based on function names

Many Q&As discuss creating a function wrapper in TypeScript, but my question is how to do the same with named methods. I am interested in writing something similar to this JavaScript code: function wrap(API, fnName, fn) { const origFn = API.p ...

Having trouble getting useFieldArray to work with Material UI Select component

I am currently working on implementing a dynamic Select field using Material UI and react-hook-form. While the useFieldArray works perfectly with TextField, I am facing issues when trying to use it with Select. What is not functioning properly: The defau ...

Using TypeORM to Retrieve Data from Many-to-Many Relationships with Special Attributes

Hey there, I'm diving into the world of TypeORM and could really use some guidance. I've been attempting to set up many-to-many relationships with custom properties following the instructions provided here However, I've run into a few iss ...

Is there a way to restrict the type of the value returned by URLSearchParams.get() to a specific union type?

When handling a search parameter in the URL, such as ?mode=view, it is important to validate the value of mode to ensure it is either 'edit' or 'view'. To achieve this, a custom type called ModeTuple is created and converted to a union ...

Ensuring Type Safety in Typescript

I have a specific requirement where I need to validate the structure of a request body to ensure it conforms to a predefined type. Is there a way or a package that can help achieve this validation? type SampleRequestBody = { id: string; name: string; ...

When setting up Webpack with TypeScript, an error is encountered related to imports

Recently, I attempted to convert my Webpack configuration from JavaScript to TypeScript but encountered numerous difficulties in the process. To kick things off, I created a basic webpack configuration file with some parts missing. Here is how my webpack.c ...

Webpack and TypeScript are throwing an error stating that `$styles` is not defined

I've encountered an issue with my typescript SharePoint spfx solution. After compiling using webpack, my $styles variable becomes undefined even though I am able to use the class names directly. It seems like there might be a configuration problem at ...