TypeScript函数泛型只能用于具有多个签名的函数重载 [英] TypeScript function generic can only work for function overload with more than one signatures

查看:284
本文介绍了TypeScript函数泛型只能用于具有多个签名的函数重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在定义一个具有通用功能的接口,例如:

I'm defining an interface with generic function like:

export interface IState {
  send: <I, E>(message: I, callback?: (e: E) => void) => IState;
}

它对于具有多个签名的类运行良好:

It works fine for classes with more than one signatures:

class Left implements IState {
  send(m: 'go-on', cb?: (e: never) => void): Left;
  send(m: 'turn-right', cb?: (e: never) => void): Right;
  send(m: 'go-on' | 'turn-right', cb?: any) {
    return m === 'go-on' ? new Left() : new Right();
  }
}

class Right implements IState {
  send(m: 'go-on', cb?: (e: never) => void): Right;
  send(m: 'turn-left', cb?: (e: never) => void): Left;
  send(m: 'go-on' | 'turn-left', cb?: any) {
    return m === 'go-on' ? new Right() : new Left();
  }
}

type Both = Left | Right;

function test(l: Both) {
  if (l instanceof Left) {
    l.send('turn-right')
      .send('turn-left')
      .send('turn-right')
      .send('turn-left');
  }
  const l2 = new Left();
  l2.send('go-on')
    .send('turn-right')
    .send('turn-left');
  l2.send('turn-right').send('turn-left');
}

但是,当我想定义一个只有一个发送签名的IState时, 我遇到了编译错误:

However when I want to define an IState with only one send signature, I got compile errors:

class CountState implements IState {
  constructor(public readonly data: number) {}
  // send(m: 'inc', cb?: (e: number) => void): CountState;
  // send(m: 'inc', cb?: (e: number) => void): CountState;
  send(m: 'inc', cb?: (e: number) => void): CountState {
    const result = this.data + 1;
    if (cb !== undefined) {
      cb(result);
    }
    return new CountState(this.data + 1);
  }
}

发送方法出错:

类型'CountState'的属性'send'不能分配给相同的 基本类型为"IState"的属性.输入'((m:"inc",cb ?:((e:number) =>无效)| undefined)=> CountState'不能分配给类型'(message:I,callback ?:((e:E)=> void)| undefined)=> IState'. 参数'm'和'message'的类型不兼容. ts(2416)

Property 'send' in type 'CountState' is not assignable to the same property in base type 'IState'. Type '(m: "inc", cb?: ((e: number) => void) | undefined) => CountState' is not assignable to type '(message: I, callback?: ((e: E) => void) | undefined) => IState'. Types of parameters 'm' and 'message' are incompatible. Type 'I' is not assignable to type '"inc"'.ts(2416)

如果我添加这两个注释行,例如

If I add those two comments lines, such that

class CountState implements IState {
  constructor(public readonly data: number) {}
  send(m: 'inc', cb?: (e: number) => void): CountState;
  send(m: 'inc', cb?: (e: number) => void): CountState;
  send(m: 'inc', cb?: (e: number) => void): CountState {
    const result = this.data + 1;
    if (cb !== undefined) {
      cb(result);
    }
    return new CountState(this.data + 1);
  }
}

它可以编译,但是看起来真的很奇怪.我该如何解决?

It compiles fine, but it looks really strange. How can I fix this?

推荐答案

我同意Titian Cernicova-Dragomir的观点,这似乎是编译器错误. IState的定义基本上说"send"属性是一个可以用任何类型的"message"调用的函数,而回调参数"e"也可以有任何类型.

I agree with Titian Cernicova-Dragomir that this seems like a compiler bug. The definition of IState basically states that the "send" property is a function which can be called with any types for "message", and the callback parameter: "e", can also have any type.

export interface IState {
    send: <I, E>(message: I, callback?: (e: E) => void) => IState;
}

同时,在示例用法中,您明确列出了可能的类型,这些类型与接口定义相矛盾.如果通过编译很奇怪.

Meanwhile, in your example usage, you are explicitly listing the possible types, which contradicts with the interfaces definition. It's weird if this passes compilation.

class Left implements IState {
    send(m: 'go-on', cb?: (e: never) => void): Left;
    send(m: 'turn-right', cb?: (e: never) => void): Right;
    send(m: 'go-on' | 'turn-right', cb?: any) {
        return m === 'go-on' ? new Left() : new Right();
    }
}

看看您包含的测试代码,无论如何都在检查未知的"Both"类型的确切类型,因此即使您只是在类中定义单独的方法,似乎也没有功能损失和正确的每个动作. eq:

Looking at the test code you included, you're checking for the exact type of the unknown "Both" type anyway, so it would seem that there is no functionality lost even if you'd just define separate methods in classes Left and Right for each action. eq:

class Left {
    turnRight(...) {
        return new Right();
    }
    keepGoin(...) {
        return new Left();
    }
}

与对每个操作使用通用的发送"方法相反.

as opposed to using the generic 'send' method for every action.

这篇关于TypeScript函数泛型只能用于具有多个签名的函数重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆