【问题标题】:How to get specific keys from interface using template literal types [REUPLOAD]? [duplicate]如何使用模板文字类型 [REUPLOAD] 从接口获取特定键? [复制]
【发布时间】:2022-10-24 17:05:27
【问题描述】:

我有以下代码为给定的数据库表接收possibleColumns 的字符串数组。然后它使用传入的source 并尝试将其与包含{source}_id 的列匹配。

例如possibleColumns 可以包含 ["id", "name", "first_id", "second_id"] 并且源是 first 然后检查任何名为 first_id 的列并返回它。

逻辑很好,但返回的类型不正确,目前它只返回可能的值作为该类型中的任何列,但我想使用模板文字类型只返回包含<value>_id 的任何值。正如在 cmets 中看到的那样,我正在尝试使用 Extract 类型但没有运气。

/**
 * Takes a list of columns for a specific table and a source and checks for any columns that
 * match `${source}_id`.
 * @template T The desired output type
 * @param possibleColumns string array of columns of type T
 * @param source The source to convert in question
 * @returns a key of one of the columns of T or undefined if not matched
 */
export function getProviderIdColumn<T>(possibleColumns: (keyof T)[], source: string) {
    // Attempt to extract only keys that contain _id at the end
    // as Extract<keyof T extends `${infer _}_id` ? keyof T : never, T>
    const providerIdColumn = `${source}_id` as keyof T;
    if (possibleColumns.includes(providerIdColumn)) {
        return providerIdColumn;
    }

电流输出

"id" | "name" | "first_id" | "second_id"

期望的输出

"first_id" | "second_id"

我对打字稿的了解不是很好,所以请忽略任何滥用的术语。

最小的工作示例

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 that
 * match `${source}_id`.
 * @template T The desired output type
 * @param possibleColumns string array of columns of type T
 * @param source The source to convert in question
 * @returns a key of one of the columns of T or undefined if not matched
 */
export function getProviderIdColumn<T>(possibleColumns: (keyof T)[], source: string) {
    // Attempt to extract only keys that contain _id at the end
    // 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";

// Returned values here are fine but I want to get the desired output.
const providerIdColumn = getProviderIdColumn<Model>(columnInfo, source);

Playground link

【问题讨论】:

    标签: typescript


    【解决方案1】:

    T.J. Crowder的原始答案

    重新上传以匿名信息,因为我无法编辑答案。

    我们可以通过使用 mapped type 来提取 _id 属性名称来做到这一点:

    /**
     * Gets a union of the literal types in `T` that end with `_id`.
     */
    type IdKeys<T extends any[]> = keyof {
        [Key in T[number] as Key extends `${string}_id` ? Key : never]: null;
    };
    

    然后在函数中使用它:

    /**
     * Takes a list of columns for a specific table and a source and checks for any columns that
     * match `${source}_id`.
     * @template ObjectType The desired output type
     * @param possibleColumns string array of columns of type T
     * @param source The source to convert in question
     * @returns a key of one of the columns of T or undefined if not matched
     */
    export function getProviderIdColumn<ObjectType>(
        possibleColumns: (keyof ObjectType)[],
        source: string
    ): IdKeys<(keyof ObjectType)[]> | undefined {
        // Sadly, we have to have a type assertion, since `source` is type `string`
        const providerIdColumn = `${source}_id` as IdKeys<(keyof ObjectType)[]>;
        if (possibleColumns.includes(providerIdColumn)) {
            return providerIdColumn;
        }
        return undefined;
    }
    

    结果是在您的示例调用中:

    const providerIdColumn = getProviderIdColumn<Model>(columnInfo, source);
    

    ...providerIdColumn 的类型是 "boardex_id" | "duedil_id" | "zoom_info_id" | undefined

    Playground example

    【讨论】:

    • 没有什么可做的“匿名”在仍然可用的question/answer。也是对 T.J. 的 ping。足以编辑该答案...
    猜你喜欢
    • 2022-10-24
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 2016-01-28
    • 2021-03-19
    • 2020-08-15
    • 2019-01-31
    • 1970-01-01
    相关资源
    最近更新 更多