【问题标题】:How can you type a functional mixin reducer?你如何输入一个功能性的 mixin reducer?
【发布时间】:2021-12-14 22:35:19
【问题描述】:

我正在学习打字稿并努力弄清楚如何适当地键入一个减少功能混合的 reducer 函数。

给定两个功能性 mixin,例如:

type FooComposable = {
  foo: string;
};
const withFoo = (composable): FooComposable => {
  composable.foo  = 'foo';

  return composable;
};

type BarComposable = {
  bar: string;
};
const withBar = (composable): BarComposable => {
  composable.bar = 'bar';

  return composable;
};

我有一个 reducer 函数,它将减少所有提供的功能 mixins:

const reduce(...fns) = fns.reduce((acc, fn) => fn(acc), {}));

reduce(withFoo); // -> { foo: 'foo' }
reduce(withBar); // -> { bar: 'bar' }
reduce(withFoo, withBar); // -> { foo: 'foo', bar: 'bar' }

如何将类型添加到 reduce() 函数(和函数式 mixins),以使减少的可组合具有预期的类型推断?

type FooComposable = {
  foo: string;
};
const withFoo = <T extends FooComposable>(composable: T): FooComposable => {
  composable.foo = 'foo';

  return composable;
};

type BarComposable = {
  bar: string;
};
const withBar = <T extends BarComposable>(composable: T): BarComposable => {
  composable.bar = 'bar';

  return composable;
};

type FunctionalMixin<T extends {}> = (composable: T) => T;
const reduce = <T extends {}>(...fns: FunctionalMixin<T>[]): T =>
  fns.reduce((acc, fn) => fn(acc), {});
/* Type '{}' is not assignable to type 'T'.
  '{}' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.  */

reduce<FooComposable & BarComposable>(withFoo, withBar); // -> { foo: 'foo', bar: 'bar' }
/* Argument of type '<T extends FooComposable>(composable: T) => FooComposable' is not assignable to parameter of type 'FunctionalMixin<FooComposable & BarComposable>'.
  Type 'FooComposable' is not assignable to type 'FooComposable & BarComposable'.
    Property 'bar' is missing in type 'FooComposable' but required in type 'BarComposable'. */


【问题讨论】:

    标签: javascript typescript functional-programming


    【解决方案1】:

    如何将类型添加到 reduce() 函数(和函数式 mixins),以便生成的缩减组合具有预期的类型推断?

    在以下示例中,result 具有正确推断的类型 Foo &amp; Bar

    Playground

    type Foo = {
        foo: string;
    };
    
    const withFoo: Mixin<Foo> = (a) => ({ ...a, foo: 'foo' });
    
    type Bar = {
        bar: string;
    };
    
    const withBar: Mixin<Bar> = (a) => ({ ...a, bar: 'bar' });
    
    type Mixin<B> = <A extends object>(a: A) => A & B;
    
    type Reduce<A extends object, T extends unknown[]> =
        T extends [] ? A :
        T extends [Mixin<infer B>, ...infer C] ? Reduce<A & B, C> :
        never;
    
    const reduce = <T extends Mixin<unknown>[]>(...fns: T): Reduce<{}, T> =>
        fns.reduce((a, fn) => fn(a), {}) as Reduce<{}, T>;
    
    const result = reduce(withFoo, withBar);
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-04
    • 2012-07-14
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 2016-03-04
    • 1970-01-01
    相关资源
    最近更新 更多