我有一个为参数定义类型的函数。参数为key
(是指定接口IBook
的键)和value
(其类型应对应于该接口中的特定键)。即如果key === 'id'
,则value
唯一可接受的类型应该是number
。
当我想创建另一个函数以将参数从onChange
事件传递给第一个函数时,就会出现问题。为了避免再次声明函数参数,我使用了Parameters
泛型,但是它的行为似乎不正确。检查下面的用法。
interface IBook {
id: number;
title: string;
isPromoted?: boolean;
}
export const editBook = <K extends keyof Required<IBook>>(
key: K,
value: Required<IBook>[K],
) => ({
type: 'EDIT_BOOK',
payload: { key, value },
});
const onChange = (...args: Parameters<typeof editBook>) => {
dispatch(editBook(...args));
};
editBook('id', 'some string'); // string not accepted here, shows error
onChange('id', 'some string'); // no error here
editBook('id', true); // boolean not accepted here, shows error
onChange('id', true); // no error here
如果我使用原始函数editBook
,则value
的键入正确-它只是与key
类型相对应的那个。如果我使用另一个,则显示错误。但是,如果我使用包装函数onChange
,则IBook
参数将接受value
中存在的任何类型。
有什么办法可以解决这个问题?
答案 0 :(得分:0)
当您使用Parameters
时,您不会捕获原始函数的类型参数,而typescript将仅使用约束条件来查找对该类型参数的任何引用,因此onChange
的签名实际上将就是这样:
(key: keyof IBook, value: Required<IBook>[keyof IBook]) => void
它将解决:
(key: "id" | "title" | "isPromoted", value: string | number | boolean) => void
允许无效呼叫。
不幸的是,没有捕获类型参数并将其转发给新函数的显式方法。从3.4开始,使用管道函数described here
有一种隐式方法function pipe<A extends any[], B, C>(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C {
return (...args: A) => bc(ab(...args));
}
function dispatch<T extends { type: string }>(action: T): void {
}
const onChange = pipe(editBook, dispatch); // generic type parameter preserved
editBook('id', 'some string'); // string not accepted here, shows error
onChange('id', 'some string'); // error now
editBook('id', true); // boolean not accepted here, shows error
onChange('id', true); // error now