I am dealing with a code snippet here that accepts a string array named possibleColumns
for a specific database table. It then takes the incoming source
and attempts to find a column containing {source}_id
.
For example, if the possibleColumns
includes
["id", "name", "first_id", "second_id"]
and the source is first
, it looks for any columns named first_id
and returns them.
The logic itself works correctly but the types returned are not accurate. Currently, it just returns any of the columns in that type as possible values. I aim to enhance this by using template literal types to specifically return values that contain <value>_id
. Despite trying to utilize the Extract
type as indicated in the comments, I have been unsuccessful so far.
/**
* Takes a list of columns for a specific table and a source, and checks for any columns matching `${source}_id`.
* @template T The desired output type
* @param possibleColumns string array of columns of type T
* @param source The source being queried
* @returns a key of one of the columns of T or undefined if no match is found
*/
export function getProviderIdColumn<T>(possibleColumns: (keyof T)[], source: string) {
// Attempting to extract only keys that end with _id
// as Extract<keyof T extends `${infer _}_id` ? keyof T : never, T>
const providerIdColumn = `${source}_id` as keyof T;
if (possibleColumns.includes(providerIdColumn)) {
return providerIdColumn;
}
Current output
"id" | "name" | "first_id" | "second_id"
Desired output
"first_id" | "second_id"
I do acknowledge my limited knowledge of TypeScript terminology, so please overlook any inaccuracies in my explanation.
Minimal working example
export interface Model {
id: number,
name: string | null,
third_id: string | null,
source: string,
first_id: string | null,
second_id: string | null,
}
/**
* Takes a list of columns for a specific table and a source, and checks for any columns matching `${source}_id`.
* @template T The desired output type
* @param possibleColumns string array of columns of type T
* @param source The source being queried
* @returns a key of one of the columns of T or undefined if no match is found
*/
export function getProviderIdColumn<T>(possibleColumns: (keyof T)[], source: string) {
// Attempting to extract only keys that end with _id
// as Extract<keyof T extends `${infer _}_id` ? keyof T : never, T>
const providerIdColumn = `${source}_id` as keyof T;
if (possibleColumns.includes(providerIdColumn)) {
return providerIdColumn;
}
return undefined;
}
// A function here returns a string array of the keys in Model.
const columnInfo: (keyof Model)[] = ["id", "name", "first_id", "source", "second_id", "third_id"];
const source = "first";
// Values returned here are correct, but I aim to achieve the desired output.
const providerIdColumn = getProviderIdColumn<Model>(columnInfo, source);