我对 TS 还很陌生,并且一直被困在这个特定问题上。
我正在使用 reduce 构建一个对象,它将对象方法包装在一个函数中。我需要该对象返回原始对象的键以及 apiDispatch 函数的承诺,就我所知。
任何帮助将不胜感激
const actions = {
getSomething: ({ id }) => ({
url: `/something/${id}`
})
};
function buildClient() {
const apiDispatch = async (data: any) => Promise;
return Object.entries(actions).reduce((acc, [key, value]) => {
acc[key] = (data: any, options: any): Promise<any> =>
apiDispatch({
...value(data),
...options
});
return acc;
}, {} as typeof actions);
}
const client = buildClient();
client.getSomething({ id: 123 }).then((res: any) => res);
acc[key]
给出以下错误 - Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
client.getSomething().then()
然后没有分配给类型链接到代码和框:
https://codesandbox.io/s/typescript-playground-export-forked-2yg63?file=/index.ts
答案 0 :(得分:1)
据我所知,getSomething
属性的末尾应该有两个参数。
const acts = {
getSomething: ({ id }: { id: string }) => ({
url: `/something/${id}`
}),
getSomethingElse: ({ name }: { name: string }) => ({
url: `/something/${name}`
})
} as const;
type Actions = typeof acts;
type Fn = (...args: any[]) => object
const apiDispatch = <T,>(data: T) => Promise.resolve(data);
type Convert<T extends Record<string, Fn>> = {
[Prop in keyof T]: <Options extends object>(data: Parameters<T[Prop]>[0], options: Options) => Promise<any>
}
type O = Convert<typeof acts>
const buildClient = <
Keys extends string,
Value extends Fn,
Rec extends Record<Keys, Value>
>(actions: Rec) =>
Object.entries<Value>(actions).reduce((acc, [key, value]) => ({
...acc,
[key]: <T, U>(data: T, options: U) => apiDispatch({
...value(data),
...options
})
}), {} as Convert<Rec>);
const client = buildClient(acts)
const result = client.getSomething({ id: 'dsf' }, {}).then(data => data) // ok
const result2 = client.getSomethingElse({ name: 'dsf' }, {}).then(data => data) // ok
const result3 = client.getSomethingElse({ id: 'dsf' }, {}).then(data => data) // expected error
友情提示,尽量避免 TS 中的突变。 Here,在我的博客中,您可以找到在 TS 中改变值可能会遇到的一些问题
答案 1 :(得分:0)
我只更改了一行就设法解决了您的问题。在这种情况下,TypeScript 不够聪明,无法理解允许在此位置进行赋值。所以我必须做的是稍微更改类型(如 Sean),然后使用 TypeScript 中的 as
运算符将其更改回来。
这是现在代码的样子:
type OverrideReturn<T extends (...args: any[]) => any, R> = (...args: Parameters<T>) => R;
const actions = {
getSomething: ({ id }: { id: any }) => ({
url: `/something/${id}`
})
};
function buildClient() {
const apiDispatch = async (data: any) => ({ name: "test object" });
return Object.entries(actions).reduce((acc, [key, value]) => {
acc[key] = (data: any, options: any): Promise<any> =>
apiDispatch({
...value(data),
...options
});
return acc;
}, {} as Record<string, any>) as {} as { [K in keyof typeof actions]: OverrideReturn<typeof actions[K], Promise<any>> };
}
const client = buildClient();
client.getSomething({ id: 123 }).then((res: any) => res);
答案 2 :(得分:-1)
出现此错误的原因是您定义了 {} as typeof actions
。有了这个,Typescript 期望您的 acc
与您的 actions
相同。但由于您希望 acc
与众不同,因此您需要为它定义一个新的返回类型。
buildClient
定义新类型,如果 actions
类型可以不时更改,您可以在此处使用 Typescript Generic Type。使用下面的新类型定义,Client
类型将是一个对象,该对象具有与泛型类型相同的属性键,每个键的值将是一个返回 Promise 的函数。type Client<T> = Record<keyof T, (data: any, options?: any) => Promise<any>>;
buildClient
定义为接收泛型类型 T
的泛型函数function buildClient<T>()
acc[key as keyof T]
,让 Typescript 知道属性键将来自泛型类型 T
。{} as Client<T>
,让 Typescript 知道 {}
是 Client<T>
类型而不是空对象。buildClient
时,只需将 <typeof actions>
放在它旁边,以便 Typescript 将所有泛型类型 T
替换为 typeof actions
const client = buildClient<typeof action>()
在所有这些更改之后,Typescript 现在将理解 client
只有一个属性 getSomething
并且它是一个返回承诺的函数。所以,最终的代码将是:
type Client<T> = Record<keyof T, (data: any, options?: any) => Promise<any>>;
const actions = {
getSomething: ({ id }) => ({
url: `/something/${id}`
})
};
function buildClient<T>(): Client<T> {
const apiDispatch = async (data: any) => Promise;
return Object.entries(actions).reduce((acc, [key, value]) => {
acc[key as keyof T] = (data: any, options: any): Promise<any> =>
apiDispatch({
...value(data),
...options
});
return acc;
}, {} as Client<T>);
}
const client = buildClient<typeof actions>();
client.getSomething({ id: 123 }).then((res: any) => res);