TypeScript:如何为函数中的任何键键入对象剩余分布

Posted

技术标签:

【中文标题】TypeScript:如何为函数中的任何键键入对象剩余分布【英文标题】:TypeScript: How to type object rest spread for any keys in function 【发布时间】: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 作为参数类型。 【参考方案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 

【讨论】:

以上是关于TypeScript:如何为函数中的任何键键入对象剩余分布的主要内容,如果未能解决你的问题,请参考以下文章

使用随机数组字符串键入对象键/属性 - TypeScript

如何为 TypeScript React 应用程序设置键/值默认状态

TypeScript - 使用专有参数键入函数的对象映射

在 TypeScript 中键入匿名对象的属性

如何为解构对象中的嵌套函数编写类型?

typescript:传递一个接受较少参数的函数 - 如何为传递的函数强制执行相同数量的参数