【问题标题】:Flow types - map Object of functions to function results流类型 - 将函数对象映射到函数结果
【发布时间】:2019-07-23 02:06:16
【问题描述】:

我正在尝试输入一个带有流的函数,给定一个 Object 类型,它接受一个对象,其中每个属性都被一个创建值的“create”函数替换。我希望能够使用键入的$ElementType 将值类型映射到$Keys,但它似乎没有正确关联键和值。

这是一个简化的例子:

// @flow

type TestType = {
  foo: number,
  bar: string,
}

declare function create<
  K: $Keys<TestType>,
  V: $ElementType<TestType, K>,
  O: {[K]: () => V}
>(obj: O): TestType

const tmp = create({
  foo: () => 5,
  bar: () => 'whatever',
})

但 flow 报告每种类型都与相反键的值不兼容。例如。 foo 的值与bar 的值不兼容:

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ tmp/syntax/flowTest.js:15:14

Cannot call create with object literal bound to obj because number [1] is
incompatible with string [2] in the return value of property foo.

 [2]  5│   bar: string,
       :
     11│   O: {[K]: () => V}
     12│ >(obj: O): TestType
     13│
     14│ const tmp = create({
 [1] 15│   foo: () => 5,
     16│   bar: () => 'whatever',
     17│ })
     18│
     19│ // type TodoValues = {
     20│ //   todos: Array<string>,


Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ tmp/syntax/flowTest.js:16:14

Cannot return 'whatever' because string [1] is incompatible with number [2].

 [2]  4│   foo: number,
       :
     13│
     14│ const tmp = create({
     15│   foo: () => 5,
 [1] 16│   bar: () => 'whatever',
     17│ })
     18│
     19│ // type TodoValues = {

现场示例:Try Flow REPL

【问题讨论】:

    标签: javascript flowtype


    【解决方案1】:

    我认为 Flow $ObjMap example 非常接近您想要的。它基本上是开箱即用的(将run 重命名为create):

    // let's write a function type that takes a `() => V` and returns a `V` (its return type)
    type ExtractReturnType = <V>(() => V) => V;
    
    declare function create<O: {[key: string]: Function}>(o: O): $ObjMap<O, ExtractReturnType>;
    
    const o = {
      foo: () => 0,
      bar: () => 'foo',
      baz: () => true,
    };
    
    type TestType = {
      foo: number,
      bar: string,
      baz: number, // Error since true is not a number
    }
    
    const p: TestType = create(o);
    

    Try Flow

    【讨论】:

    • 啊,是的,这正是我想要的。谢谢!除非这很简单,否则我可以提出后续问题,但是知道如何使 o 的值允许任意值或函数吗?例如const o = { foo: () =&gt; 5, bar: 'barrrr'}
    • 试试这个。我不确定它是否完全安全,但它似乎在大多数情况下都有效 (Try Flow)
    • 到目前为止,我还没有发现任何不安全的方法。比我预期的要简单。谢谢!
    【解决方案2】:

    这两个属性中的一个 foo / bar 可以传递给 function obj param创建。你不能把它们放在一起,因为你有UnionType

    K: $Keys<TestType>, // UNION: number | string
    V: $ElementType<TestType, K>, // UNION: foo | bar
    O: {[K]: () => V} // UNION: foo: () => number | bar: () => string
    

    这行得通:

    type TestType = {
      foo: number,
      bar: string,
    }
    
    declare function create<
      K: $Keys<TestType>,
      V: $ElementType<TestType, K>,
      O: {[K]: () => V}
    >(obj: O): TestType
    
    const foo = create({ foo: () => 5 })
    const bar = create({ bar: () => 'whatever' })
    

    【讨论】:

      猜你喜欢
      • 2021-02-09
      • 2020-05-16
      • 2023-01-29
      • 1970-01-01
      • 2020-03-30
      • 1970-01-01
      • 2012-08-24
      • 1970-01-01
      • 2020-02-10
      相关资源
      最近更新 更多