Tips for creating an array that aligns with the keys of a type in TypeScript

Currently, I am utilizing the Kysely SQL builder for JS based on Vercel's recommendation, despite the limited documentation and community support. This SQL builder is fully typed, allowing you to create a db object with a schema that recognizes table names and attributes automatically.

import 'dotenv/config'
import { createKysely } from '@vercel/postgres-kysely'
import { DB } from 'kysely-codegen'

export const db = createKysely<DB>()
export { sql } from 'kysely'

The DB is generated directly from the PostgreSQL schema and stored in the kysely-codegen node_modules folder. Here is a brief snippet of how it looks:

export interface MyTable {
  id: string
  foo: string
  bar: boolean
}

export interface DB {
  my_table: MyTable
}

My query revolves around the select function, which requires an array of keys from MyTable when querying my_table.

const record = await db
  .selectFrom('my_table')
  .select(['foo', 'id'])
  .executeTakeFirst()

While this works well, I encounter an issue when attempting the following:

// simulate not knowing what the input is
// as if you were making a browser JSON API request
const json = JSON.parse(fs.readFileSync('test.json'))
const selectKeys = Object.keys(json)

const record = await db
  .selectFrom('my_table')
  .select(selectKeys)
  .executeTakeFirst()

This results in an error:

Argument of type 'string[]' is not assignable to parameter of type 'SelectArg<DB, "my_table", SelectExpression<DB, "my_table">>'.

To fix this, I modify the code as follows:

const record = await db
  .selectFrom('my_table')
  .select(selectKeys as Array<keyof MyTable>)
  .executeTakeFirst()

To ensure the selectKeys array aligns with the keys of my_table, I have created a function:

const MY_TABLE_KEYS: Array<keyof MyTable> = ['id', 'foo', 'bar']

function getKeys(json) {
  const keys = []
  for (const key in json) {
    if (MY_TABLE_KEYS.includes(key)) {
      keys.push(key)
    }
  }
  return keys
}

While this approach works, there are some challenges with the getKeys function. I have provided a TypeScript playground here to highlight the challenges faced.

My main query is on how to properly type the keys to be passed to the .select method.

Answer №1

If you're on the hunt for a type predicate or type guard, look no further. Type predicates are essentially functions that affirm that an argument is of a specific type if the function returns true. For instance, a basic predicate could resemble this:

(key: string): key is keyof MyTable => { return true; }

In the straightforward example above, a true value is always returned. To make this concept more practical, you'd need to verify if the key belongs to the known keys. The following example can guide you towards your desired outcome.

interface MyTable {
    id: string;
    foo: string;
    bar: boolean;
}

const json: Partial<MyTable> = { id: "hello", foo: "world" };

// Extract keys from json, then remove any keys not part of MyTable
// our filter acts as a predicate
const keys = Object.keys(json).filter((key): key is keyof MyTable =>
    ["id", "foo", "bar"].includes(key),
);

const record: Partial<MyTable> = {};
keys.forEach((key) => (record[key] = json[key]));

You may encounter challenges with record[key] = json[key] due to the potential undefined value of json[key] (since it's a partial);

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

How can I receive the response from a GET request using React Query? I am currently only able to get the response

I have created a search component where I input a name in the request, receive a response, and display it immediately. However, after the first input submit, I get undefined in response. Only after the second submit do I get the desired response. The tec ...

Create a constant object interface definition

Is there a way to create an interface for an object defined with the as const syntax? The Events type does not work as intended and causes issues with enforcement. const events = { // how can I define an interface for the events object? test: payload ...

Extending an External Object with Custom Properties in TypeScript

When working with an external library, I often find myself needing to add new properties to passed-in parameters. Instead of using (<any>conv.data) due to the compiler error Object is of type 'unknown', I'm curious if there's a mo ...

What is the best way to interrupt the current song playing?

I am currently working on developing an audio player using reactjs that has a design similar to this https://i.sstatic.net/Hnw0C.png. The song boxes are rendered within a map function, and when any song box is clicked, it should start playing. However, I a ...

In Next.js, the switch button remains in the same state even after the page is refreshed

Is there a solution for this issue? I am currently developing a switch button for a configuration page. The problem arises when I toggle the switch from active to maintenance mode, save it successfully, but upon refreshing the page, the switch reverts back ...

Error message: There appears to be a type error within the labelFunc of the KeyBoardDatePicker component in the Material-UI

I am currently working with a material-ui pickers component: <KeyboardDatePicker value={selectedDate} onChange={(_, newValue) => handleClick(newValue)} labelFunc={renderLabel} disableToolbar variant='inline' inputVariant=& ...

Is it possible for OpenFin to store logs in a secure database and what is the process for accessing logs located at %LocalAppData%openfinapps<app>app.log

System Information Here are the details of the system setup: OpenFin Process Manager Version: RVM = 8.1.0.4 Node.js: v16.15.0 Windows 10 Angular Application with C# .NET backend Issue: The current setup saves all application logs locally on users' ...

What is the method to group a TypeScript array based on a key from an object within the array?

I am dealing with an array called products that requires grouping based on the Product._shop_id. export class Product { _id: string; _shop_id: string; } export class Variant { variant_id: string; } export interface ShoppingCart { Variant: ...

Angular is patiently awaiting the completion of the subscription

Currently, I am in the process of developing a test application using Angular. The challenge arises when I attempt to retrieve data through a Get request and then return a value based on that data. The code snippet below outlines the scenario: public getN ...

Exploring Angular 4 with the power of Rangy modules

I've recently started working with Angular 4 and decided to create a basic app by forking the Angular quickstart. Now, I'm facing a challenge as I try to incorporate Rangy into my project. In my package.json, the dependencies are listed as follo ...

Choose a specific div element from a collection of dynamically generated divs in Angular

I have been working on a code to dynamically generate div elements using the *ngFor directive. Here is what I have so far: <div *ngFor = "let item of Items"> <p>Item : {{item}} </p> </div> The challenge I encountered is that w ...

Variable type linked to interface content type

Is it possible to link two fields of an interface together? I have the following interface: export interface IContractKpi { type: 'shipmentVolumes' | 'transitTime' | 'invoices'; visible: boolean; content: IKpiContent; } ...

Exploring the method to retrieve a dynamically added property in Typescript

My React Component Loader receives certain props. The contentAlign property is only available when the local property exists and its value is 'relative'. I am encountering an error when trying to include contentAlign in the props, and I cannot ...

Provide the remaining arguments in a specific callback function in TypeScript while abiding by strict mode regulations

In my code, I have a function A that accepts another function as an argument. Within function A, I aim to run the given function with one specific parameter and the remaining parameters from the given function. Here's an example: function t(g: number, ...

Enhancing Material UI v4 Themes using TypeScript

I am attempting to implement my own custom palette option in the theme section, but I am struggling with how to do the augmentation part using TypeScript. So far, I have created a file named "material-ui.d.ts" and inside it, I only have: import { PaletteO ...

Guide to Validating Fields in Angular's Reactive Forms After Using patchValue

I am working on a form that consists of sub-forms using ControlValueAccessor profile-form.component.ts form: FormGroup; this.form = this.formBuilder.group({ firstName: [], lastName: ["", Validators.maxLength(10)], email: ["", Valid ...

Modify the ShortDate formatting from "2020/06/01" to "2020-06-01"

I am looking to modify the shortDate format in my template file. Currently, when I try to change it to use "-", it still displays the date with "/". What I actually want is for the output to be formatted as yyyy-MM-dd. <ngx-datatable-column name="C ...

Leveraging TypeScript with Angular components

Situation: On my website, I have a section called the "main page" where all available books are displayed. The "main page" is represented by the blue box in the image provided and serves as a key component on my site. Additionally, there is a separate co ...

Guide to generating a text string by utilizing the foreach loop

Is there a way to combine text strings from interfaces into a single file for display in UI? The current code is generating separate files for each interface. How can I achieve the expected result of having all interfaces in one file? Additionally, is it ...

Deduce the types of parameters in nested functions based on the parent object

Having encountered a challenging obstacle in my Typescript journey, I find myself facing a dilemma with building a command-parsing utility. My aim is to incorporate type hints within configuration objects. Let's delve into the code example below; int ...