根据参数类型不同的返回类型?

问题描述 投票:0回答:2

我想要一个接口,我知道参数将是几种不同类型中的一种(来自第三方库),并且根据它的类型,返回类型将会改变,某些类型也来自第三方库,或者是像 void 或 null 这样的基本类型。

这是复制我的问题的最简单的代码

type foo = {
  statusCode: number;
  body: string;
}
type fooReturn = string; // in reality, this could be a complex type

type bar = {
  results: [];
}
type barReturn = number; // in reality, this could be a complex type

interface foobar {
  myFunc<T extends (foo | bar)>(event: T): T extends foo ? fooReturn : barReturn;
}

class myClass implements foobar {
  // the below code errors
  myFunc(event: foo) { // we tell TS that the param is of type foo
    return 'hello' // so the return must be a string
  }
}

错误是

Property 'myFunc' in type 'myClass' is not assignable to the same property in base type 'foobar'.
  Type '(event: foo) => string' is not assignable to type '(event: T) => T extends foo ? string : number'.
    Types of parameters 'event' and 'event' are incompatible.
      Type 'T' is not assignable to type 'foo'.
        Type 'foo | bar' is not assignable to type 'foo'.
          Type 'bar' is missing the following properties from type 'foo': statusCode, body

javascript typescript interface
2个回答
0
投票

我认为处理此问题的正确方法是使用函数重载。然后,您可以使用类型保护来缩小

event
参数并返回正确的类型。

type Foo = {
  statusCode: number;
  body: string;
};
type FooReturn = string;

type Bar = {
  results: [];
};
type BarReturn = number;

interface FooBar {
  myFunc(event: Foo): FooReturn;
  myFunc(event: Bar): BarReturn;
  myFunc(event: Foo | Bar): FooReturn | BarReturn;
}

class myClass implements FooBar {
  myFunc(event: Foo): FooReturn;
  myFunc(event: Bar): BarReturn;
  myFunc(event: Foo | Bar): FooReturn | BarReturn{
    if ("results" in event) {
      return 666;
    } else {
      return "hello";
    }
  }
}

TypeScript 游乐场


0
投票

这里的问题似乎是您错误地范围了您的意图的generic类型参数。类型

interface Foobar {
    myFunc<T extends Foo | Bar>(event: T): T extends Foo ? FooReturn : BarReturn;
}

是具有泛型方法的特定类型。泛型方法的泛型类型参数的范围仅限于调用签名,这意味着 caller 决定其中的类型参数。如果我想实现一个

Foobar
,那么它的
myFunc()
方法必须允许调用者使用他们想要的任何
T
进行调用。它必须支持两者
myFunc(event: Foo): FooReturn
myFunc(event: Bar): BarReturn
。但是
MyClass
没有正确实现;它只支持
Foo
而不支持
Bar

相反,您可能想要

interface Foobar<T extends Foo | Bar> {
    myFunc(event: T): T extends Foo ? FooReturn : BarReturn;
}

这是一个通用类型,具有特定方法。泛型类型的泛型类型参数的范围仅限于类型本身,这意味着implementer 决定其中的类型参数。根据该定义,您需要决定是实施

Foobar<Foo>
还是
Foobar<Bar>
。一旦做出决定,
T
的类型参数就会被选择并固定。
myFunc()
的呼叫签名不是通用的。并且您的
MyClass
确实正确实施了
Foobar<Foo>
:

class MyClass implements Foobar<Foo> {
    myFunc(event: Foo) { // okay
        return 'hello'
    }
}

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.