【问题标题】:TypeScript: How to type object rest spread for any keys in functionTypeScript:如何为函数中的任何键键入对象剩余分布
【发布时间】:2021-05-17 05:16:03
【问题描述】:

我有一个函数,它接受一个对象并返回一个对象。它返回整个传入对象,但添加了一个键。对象的形状是未知的,所以它可以有任何键,但它必须有 2 个特定的键。

const myFunction = ({
  num1,
  num2,
  ...rest
}: {
  num1: number;
  num2: number;
}) => ({
  num1,
  num2,
  sum: num1 + num2,
  ...rest,
});

myFunction({ num1: 4, num2: 3, foo: 'bar' });
// or myFunction({ num1: 4, num2: 3, baz: 'qux', quux: 'quuz' });

TypeScript 在这里大喊foo

Argument of type '{ num1: number; num2: number; foo: string; }' is not assignable to parameter of type '{ num1: number; num2: number; }'.
  Object literal may only specify known properties, and 'foo' does not exist in type '{ num1: number; num2: number; }

这是一个简化的例子。

这是我的实际功能以及我如何尝试使用 extends 解决它。

import type { NextApiRequest, NextApiResponse } from 'next';
import { getSession } from 'utils/sessions';

const withAuthentication = async <
  T extends {
    request: NextApiRequest;
    response: NextApiResponse;
  },
  K extends T
>({
  request,
  response,
  ...rest
}: T): Promise<
  {
    userSession: {
      issuer: string;
      publicAddress: string;
      email: string;
    };
  } & K
> => {
  const userSession = await getSession(request);

  return { request, response, userSession, ...rest };
};

export default withAuthentication;

实际的错误是这样的。

Type '{ request: NextApiRequest; response: NextApiResponse<any>; userSession: any; } & Omit<T, "request" | "response">' is not assignable to type '{ userSession: { issuer: string; publicAddress: string; email: string; }; } & K'.
  Type '{ request: NextApiRequest; response: NextApiResponse<any>; userSession: any; } & Omit<T, "request" | "response">' is not assignable to type 'K'.
    '{ request: NextApiRequest; response: NextApiResponse<any>; userSession: any; } & Omit<T, "request" | "response">' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint '{ request: NextApiRequest; response: NextApiResponse<any>; }'.

你怎么能键入这样的函数?

【问题讨论】:

  • 不确定这是否是个好主意; { num1: number; num2: number; } &amp; any 作为参数类型。

标签: typescript typescript-typings spread-syntax typescript-types


【解决方案1】:

使用 rest 参数进行解构使得它难以进行类型检查,但如果您只是扩展参数对象并添加 userSession 属性,您最终会得到一个相当易读的解决方案:

const withAuthentication = async <
  T extends {
    request: NextApiRequest;
    response: NextApiResponse;
  }
>(arg: T): Promise<{
    userSession: {
      issuer: string;
      publicAddress: string;
      email: string;
    };
  } & T> => {
  const userSession = await getSession(arg.request);
  return { ...arg, userSession };
};

(TypeScript playground)

【讨论】:

    【解决方案2】:

    这段代码也可以编译,但我不知道它是否是最好的方法。

    import { UserSession } from 'features/user-authentication/types';
    import type { NextApiRequest, NextApiResponse } from 'next';
    import { getSession } from 'utils/sessions';
    
    const withAuthentication = async <
      T extends {
        request: NextApiRequest;
        response: NextApiResponse;
      }
    >({
      request,
      response,
      ...rest
    }: T): Promise<
      {
        request: NextApiRequest;
        response: NextApiResponse;
        userSession: UserSession;
      } & Omit<T, 'request' | 'response'>
    > => {
      const userSession = await getSession(request);
    
      if (userSession) {
        return { request, response, userSession, ...rest };
      }
    
      throw new Error('Unauthenticated');
    };
    
    export default withAuthentication;
    

    【讨论】:

      【解决方案3】:

      您可以使用generics

      演示:https://repl.it/@chvolkmann/InternalFrugalCopyleft

      interface MyArgs {
        a: number
        b: number
      }
      
      const doSomething = <A extends MyArgs>(args: A) => ({
        ...args,
        sum: args.a + args.b
      })
      
      console.log(doSomething({ a: 10, b: 5, foo: 'bar' }))
      // Output:
      // { a: 10, b: 5, foo: 'bar', sum: 15 }
      

      【讨论】:

        猜你喜欢
        • 2019-01-13
        • 1970-01-01
        • 2022-11-30
        • 2022-12-12
        • 1970-01-01
        • 2021-08-27
        • 1970-01-01
        • 2022-01-27
        • 2021-09-16
        相关资源
        最近更新 更多