类型 'any[]' 不可分配给类型“[id: string]”
Type 'any[]' is not assignable to type '[id: string]'
我正在尝试创建一个通用 API 类型,它的属性是 return 承诺的功能。
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 类型实际上要求什么,它将其所有 key/value 对定义为具有任意数量的参数,这在技术上是正确的,但会暴露 API const 不正确,允许你做这样的事情
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
assertion.
const api = {
get: (id: User['id']): Promise<Response> => Promise.resolve({
data: {
id,
name: 'name'
}
}),
} //as const
// {
// get: (id: User['id']) => Promise<Response>;
// }
第三个选项:创建一个包装函数,它将推断一个 return 值,这是 TS 中的一个常见技巧,滥用 function inferencing 来确定基于赋值的类型。如果你想使用 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
值的键组成,并且它们的值必须是一个函数,它总是returns Promise<Response>
,这个可以根据需要修改。
查看 Playground 以找到最适合您的选项。
我正在尝试创建一个通用 API 类型,它的属性是 return 承诺的功能。
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 类型实际上要求什么,它将其所有 key/value 对定义为具有任意数量的参数,这在技术上是正确的,但会暴露 API const 不正确,允许你做这样的事情
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
assertion.
const api = {
get: (id: User['id']): Promise<Response> => Promise.resolve({
data: {
id,
name: 'name'
}
}),
} //as const
// {
// get: (id: User['id']) => Promise<Response>;
// }
第三个选项:创建一个包装函数,它将推断一个 return 值,这是 TS 中的一个常见技巧,滥用 function inferencing 来确定基于赋值的类型。如果你想使用 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
值的键组成,并且它们的值必须是一个函数,它总是returns Promise<Response>
,这个可以根据需要修改。
查看 Playground 以找到最适合您的选项。