类型"any[]"不能分配给类型"[id:字符串]"



我正在尝试创建一个通用的API类型,它的属性是返回Promise的函数。

export type API = {
[key: string]: <Params extends any[], Response>(...params: Params) => Promise<Response>,
}
export interface UserResponse {
data: User
}
export interface User {
id: string;
name: string;
}
export const api: API = {
get: (id: User['id']): Promise<UserResponse> => Promise.resolve({
data: {
id,
name: 'name'
}
})
};

这给了我get:上的错误

Type '(id: User['id']) => Promise<UserResponse>' is not assignable to type '<Params extends any[], Response>(...params: Params) => Promise<Response>'.
Types of parameters 'id' and 'params' are incompatible.
Type 'Params' is not assignable to type '[id: string]'.
Type 'any[]' is not assignable to type '[id: string]'.
Target requires 1 element(s) but source may have fewer.

如何使泛型类型接受id: string作为API方法的参数?

游乐场

这是因为您使用的模板文字不正确。最简单(也是最"错误"的答案(是以下。。。这将突破许多用例,并且您的泛型。。。

export type API = {
[key: string]: (...params: any[]) => Promise<Response>,
}

相反,让走你需要的路线这个通用:

让我们问问自己API类型实际要求的是什么,它将其所有键/值对定义为具有任何数量的参数,这在技术上是正确的,但会错误地暴露API常量,从而允许您执行类似的操作

API.get() //<-- No error thrown here, since it uses the API typing correctly.
API.get(true, false, 'foo', 'bar') //<-- This also is allowed

因此,我们为什么会抛出此错误Target requires 1 element(s) but source may have fewer.基本上概述了在API的导出端,有人可能会错误地使用它。

第一个选项:显式键入API的所有成员。这是确保API形状的首选和最安全的选项。

export type API = {
get: (id: string) => Promise<Response>
//set: (id: string) => Promise<Response>
//...
}

第二个选项:让TS推断您的API。对于不变性,指定as const断言。

const api = {
get: (id: User['id']): Promise<Response> => Promise.resolve({
data: {
id,
name: 'name'
}
}),
} //as const
// {
//   get: (id: User['id']) => Promise<Response>;
// }

第三种选择:创建一个包装函数,该函数将推断返回值,这是TS中滥用函数推断来根据赋值确定类型的常见技巧。如果您想使用TS强制API具有特定类型,特别是如果多个开发人员将接触此代码(但不想显式键入API(,这是最好的选择。就可读性而言,这也是最糟糕的选择,对那些可能不熟悉TS的人来说,这会混淆类型,并可能使追踪api更困难

const returnAPI = <
T extends Record<string, (...args: any[]) => Promise<Response>>
>(o: T): {
[K in keyof T]: T[K]
} => o
const api = returnAPI({
get: (id: User['id']): Promise<Response> => Promise.resolve({
data: {
id,
name: 'name'
}
}),
})

我们使用extends关键字来表示T必须具有特定的形状,在这种情况下,由扩展string值的键组成,并且它们的值必须是始终返回Promise<Response>的函数,这可以根据需要进行修改。

  • 更多关于映射类型的阅读

查看游乐场,找到最适合您的选择。

相关内容

最新更新