TypeScript:如何为函数中的任何键键入对象剩余分布
TypeScript: How to type object rest spread for any keys in function
我有一个接受一个对象和 returns 一个对象的函数。它returns整个传入的对象,只是加了一个key。对象的形状未知,所以它可以有任何键,但它必须有 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>; }'.
你怎么能输入这样的函数?
您可以使用 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 }
此代码也可以编译,但我不知道它是否是最佳方法。
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;
使用 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 };
};
我有一个接受一个对象和 returns 一个对象的函数。它returns整个传入的对象,只是加了一个key。对象的形状未知,所以它可以有任何键,但它必须有 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>; }'.
你怎么能输入这样的函数?
您可以使用 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 }
此代码也可以编译,但我不知道它是否是最佳方法。
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;
使用 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 };
};