TypeScript:为什么Parameters泛型接受错误的参数?

时间:2019-04-12 09:29:44

标签: javascript reactjs typescript

我有一个为参数定义类型的函数。参数为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中存在的任何类型。

有什么办法可以解决这个问题?

1 个答案:

答案 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