如何防止根据打字稿中的一般约束调用函数?

时间:2020-05-21 07:32:48

标签: typescript

作为练习,我将在打字稿中实现简单的代数数据类型。 我想实现ap函数,以使其仅在包装器包含函数时才可调用。 这就是我想要使用它的方式:

Identity.of(x => x + 1).ap(Identity.of(5)); // This should work and return an Identity(6)

Identity.of(5).ap(...); // This should make the compiler emit an error

我试图用通用条件来定义它:

type Func<T, U> = (p: T) => U;

interface Identity<T> {
  map<U>(fn: Func<T, U>): Identity<U>;
  ap<U, V>(id: Identity<U>): T extends Func<U, V> ? Identity<V> : never;
}

function of<T>(value: T): Identity<T> {
  return {
    map: fn => of(fn(value)),
    ap: id => id.map(value)
  };
}

但是出现以下错误:

Type 'Identity<V>' is not assignable to type 'T extends Func<U, V> ? Identity<V> : never'.(2322)
input.ts(5, 3): The expected type comes from the return type of this signature.

Argument of type 'T' is not assignable to parameter of type 'Func<U, V>'.

这在打字稿中有可能做到吗?

1 个答案:

答案 0 :(得分:0)

经过长时间的暴力破解后,我找到了使这种类型变得安全的方法:

type Func<T, U> = (p: T) => U;

interface Identity<T> {
  map<U>(fn: Func<T, U>): Identity<U>;
  ap(id: T extends Func<infer U, any> ? Identity<U> : never): T extends Func<any, infer U> ? Identity<U> : never;
}

function of<T>(value: T): Identity<T> {
  return {
    map: fn => of(fn(value)),
    ap: id => {
      const fn: unknown = value;

      return id.map(fn as Func<unknown, unknown>) as T extends Func<any, infer U> ? Identity<U> : never;
    }
  };
}

推断接口定义中的类型有助于链式操作在链接操作时保存类型,并使所有类型安全。 在编写实现时,我们必须使用typecast来帮助打字稿。

相关问题