【问题标题】:How do I define a type based on the query projection如何根据查询投影定义类型
【发布时间】:2026-01-27 17:50:01
【问题描述】:

有没有办法在 TypeScript 中定义一些通用的动态类型,这样我就可以根据投影参数定义类型?

假设您要执行数据库查询,或者您正在执行 GraphQL 请求。 你会有一个类似的功能

interface Person {
  id: string;
  firstName: string;
  lastName: string;
}

function getPeople(projection: (keyof Person)[]): Promise<Partial<Person>[]> {...}

我的意思是,如果我现在执行getPeople(['id', 'firstName']),那么返回的对象将永远不会有任何属性lastName,因为投影被配置为永远不会将其加载到内存中。有什么方法可以在类型级别上表明这一点,而不是简单地使用仍然允许我引用未初始化属性的Partial&lt;Person&gt;

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    这里的线索是我们需要将getPeople 设为泛型,这样我们就可以在返回类型中引用参数的类型。这应该可以实现您想要实现的目标:

    interface Person {
      id: string;
      firstName: string;
      lastName: string;
    }
    
    type Fields<P, keys extends keyof P> = {
      [key in keys]: P[key];
    };
    
    declare function getPeople<keys extends keyof Person>(
      projection: keys[]
    ): Promise<Array<Fields<Person, keys>>>;
    

    【讨论】:

    • TypeScript 有时可能是这样的。我发现问自己“我如何根据输入来描述输出”,创建一个执行此操作的类型(在我们的例子中为 Fields),然后在我们的通用函数中引入一个类型参数来调用我们之前创建的类型。
    【解决方案2】:

    你需要做的就是这个

    function getPeople<K extends keyof Person>(projection: K[]):
    Promise<Pick<Person, K>[]>
    

    【讨论】:

      【解决方案3】:

      您可以将属性设为可选。使用? 键使其可选。

       interface Person {
            id: string;
            firstName?: string;
            lastName?: string;
          }
      
         function getPeople(projection: (keyof Person)[]): Promise<Partial<Person>[]> 
         {...}
      

      现在除了id,所有属性都是可选的。

      【讨论】:

      • 这很好,但这不是我的目标。我想要这个电话 -(await getPeople(['id']))[0].firstName - 给我一个编译器错误,说“'firstName' 在 X 类型上不存在”
      • 定义这样的返回类型function getPeople(projection: (keyof Person)[]): Promise&lt;Person[]&gt; {...}试试这个我希望它会工作
      • 好吧...这通常有效,但在这种情况下,当我调用 person.lastName 时,整个事情编译得很好,我得到了一个值 undefined,而我希望它变得不可能首先编译为 JS,早在我运行它之前,如果我曾经引用过 lastName 属性。您提出的解决方案并非如此