映射类型+函数参数enigma

时间:2018-04-16 13:44:14

标签: typescript redux

下面的当前示例仍然不能完全按照我的意愿行事(例如:操作redux减速器的函数)。此函数输出所需类型但允许不需要的输入(c: 'hello')。这里似乎真的需要使用currying来按照事物的顺序欺骗编译器。

type Reducer<State> = (s: State, p: any) => State

const reducerMap = <State>(s: State) => <
  ScopedReducers extends { [k in keyof State]: Reducer<State[k]> }
>(
  input: ScopedReducers
): { [k in keyof ScopedReducers]: Reducer<State> } => {
  return undefined as any
}

const state = { a: 1, b: "2" }
const mapped = reducerMap(state)({
  a: state => state + 1,
  b: state => state + "_",
  c: "hello",
})
  • ScopedReducers是一个与State有某种关系的对象(每个键都是Reducer<State[k]>),但是有自己的一部分(减速器有效负载)。 ScopedReducers应该只包含State也有的密钥。
  • 如果我将ScopedReducers直接指定给其约束,则其函数输入将正确验证。如果我在State中放入一个不存在的额外密钥,编译器将会出错,如预期的那样。
    • 另一方面,在构造函数return时,我无法重用Reducer中的payload部分。此类型将被删除为any
  • 如果我说ScopedReducers扩展了它的约束,它的类型不会被删除,并且可以在编写动态映射函数返回时使用。
    • 另一方面,由于现在我使用extends,函数参数现在接受无关键(例如:e : 2)。关系验证仍适用于适用的密钥。

“真正的野兽”是this personal project上这个文件的最后一个函数,它也有一个“keyof”问题,我认为可能无法解决......

1 个答案:

答案 0 :(得分:2)

不要过多担心代码中发生的事情以及表面上的问题,我认为您正试图让ScopedReducers成为所谓的exact type,其中包含完全指定的属性:不少也不多。不幸的是,这种类型还不存在于该语言中。幸运的是,由于conditional types是在TypeScript 2.8中引入的,现在a way要求类型参数的行为类似于确切类型,这就是您需要的所有内容。

让我们介绍Exactify<T, X>

type Exactify<T, X extends T> = T & {
  [K in keyof X]: K extends keyof T ? X[K] : never
}

并想象一下当某个X的泛型类型参数Exactify<T, X>被约束为T时会发生什么:

declare function exactlyFoo<X extends Exactify<Foo, X>>(x: X): void;

X extends Exactify<Foo, X>是什么意思?如果X只包含与Foo相同的密钥,则X extends Exactify<Foo, X>仅表示X extends T & X,只是X extends T。但是,如果X甚至在extraKey中没有一个密钥(比如Foo),则X extends Exactify<Foo, X>会变为X extends T & X & { extraKey: never },除非属性{{1},否则这是不可能的类型extraKey。实际上,这意味着您无法添加额外的密钥。

如果我将never应用于您的代码,则会变为:

Exactify<>

使用它:

const reducerMap = <State>(s: State) => <
  ScopedReducers extends Exactify<
  { [k in keyof State]: Reducer<State[k]> }, ScopedReducers>>(
    input: ScopedReducers
  ): { [k in keyof ScopedReducers]: Reducer<State> } => {
  return undefined as any
}

您根据需要在属性const state = { a: 1, b: "2" } const mapped = reducerMap(state)({ a: state => state + 1, b: state => state + "_", c: "hello", // error! }) 处收到错误。希望有所帮助。祝你好运!