typescript 在不同对象类型上运行相同方法的类型脚本

eqoofvh9  于 2022-12-05  发布在  TypeScript
关注(0)|答案(4)|浏览(156)

我想创建一个函数,它接受objvalue作为参数,并使用传递的值运行对象方法add。不幸的是,对象可以是AB类型。根据对象类型,方法add接受stringnumber。我该如何实现呢?

class A {
  add(a: number) {
    return 10 + a
  }
}

class B {
  add(a: string) {
    return 'ten' + a
  }
}

我试着做这样的事情,但 typescript lints它(我明白这一点)。

const runObejctMethod = (obj: A | B, value: string | number) =\> {
obj.add(value)
}

错误:

TS2345: Argument of type 'string | number' is not assignable to parameter of type 'never'.   Type 'string' is not assignable to type 'never'
jgzswidk

jgzswidk1#

若要建立可接受不同型别对象的函式,并以传递的值执行其add方法,您可以使用型别保护来检查对象的型别,然后呼叫适当的方法。
以下是如何实现此函数的示例:

class A {
  add(a: number) {
    return 10 + a;
  }
}

class B {
  add(a: string) {
    return "ten" + a;
  }
}

function runAdd(obj: A | B, value: any) {
  if (obj instanceof A || ) {
    return obj.add(value);
  } else if (obj instanceof B) {
    return obj.add(value);
  }
}

const a = new A();
const b = new B();

console.log(runAdd(a, 5));  // Output: 15
console.log(runAdd(b, "hello"));  // Output: "tenhello"

在本例中,runAdd函数接受类型为A或B的对象obj和任何类型的值value。然后,它使用类型保护检查obj的类型,并使用传递的值调用相应的add方法。然后,您可以使用此函数调用类型为A或B的对象的add方法,该对象具有任何类型的值。

zbsbpyhn

zbsbpyhn2#

您可以尝试使用类型保护来确定对象的类型,然后调用正确的方法。您可以通过使用typeof运算符检查对象的类型,或者通过检查对象上是否存在特定的属性来实现这一点。
下面是使用typeof运算符的示例:

const runObejctMethod = (obj: A | B, value: string | number) => {
  if (typeof obj === 'A') {
    obj.add(value as number);
  } else {
    obj.add(value as string);
  }
}

在这个例子中,我们使用typeof操作符来检查obj的类型。如果它是A的一个示例,我们调用add方法,并使用as关键字显式键入一个数字。否则,我们调用add方法,并使用一个字符串显式键入一个值。
也可以通过检查对象上是否存在特定属性来使用类型保护。例如,可以将名为isA的属性添加到A类,并在类型保护中使用它,如下所示:

class A {
  isA = true;
  add(a: number) {
    return 10 + a
  }
}

class B {
  add(a: string) {
    return 'ten' + a
  }
}

const runObejctMethod = (obj: A | B, value: string | number) => {
  if (obj.isA) {
    obj.add(value as number);
  } else {
    obj.add(value as string);
  }
}

在本例中,我们检查obj对象的isA属性是否存在。如果存在,我们就知道objA的示例,并且我们调用add方法,该方法带有一个显式类型为number的值。如果isA属性不存在,我们知道objB的一个示例,并且我们调用add方法,该方法带有一个显式类型化为字符串的值。

8hhllhi2

8hhllhi23#

您可以使用泛型

const runObejctMethod2 = <C extends {add(v: any): any}>(obj: C, value: Parameters<C['add']>[0]) => {
    obj.add(value)
}

还有其他方法(如overloaning),但它们可能需要使用as或长泛型进行转换

plupiseo

plupiseo4#

您可以使用一般条件约束的函式签章来接受add方法与条件约束相容的对象。
您也可以使用型别公用程式,从您选择的特定类别定义条件约束的相容性。
我在下面代码的注解中对此进行了更多的解释:
TSPlayground

class A {
  add (value: number): number {
    return 10 + value;
  }
}

class B {
  add (value: string): string {
    return 'ten' + value;
  }
}

class C {
  add (value: { num: number }): { num: number } {
    return { num: 10 + value.num };
  }
}

function runObejctMethod <T extends Parameters<(A | B)['add']>[0]>(
  obj: { add: (value: T) => T },
  value: T,
): void {
  const result = obj.add(value);
  console.log(result);
}

// The constraint expression above "Parameters<(A | B)['add']>[0]" means:
// "a union of the type of the first parameter of A.add or B.add",
// so — in this case — it means "string | number":
type Constraint = Parameters<(A | B)['add']>[0];
   //^? type Constraint = string | number

// You could add more compatible classes to the union
// to extend the accepted types in the constraint,
// for example: Parameters<(A | B | C | D)['add']>[0]

// --------------------

// Usage:

const a = new A();
const b = new B();
const c = new C();

// Ok:
runObejctMethod(a, 1); //=> Logs: 11
runObejctMethod(b, ' thousand'); //=> Logs: "ten thousand"

// Not ok (as expected):
runObejctMethod(a, ' thousand'); /*
                   ~~~~~~~~~~~
Argument of type 'string' is not assignable to parameter of type 'number'.(2345) */

runObejctMethod(b, 1); /*
                   ~
Argument of type 'number' is not assignable to parameter of type 'string'.(2345) */

runObejctMethod(c, { num: 1 }); /*
                ~
Argument of type 'C' is not assignable to parameter of type '{ add: (value: string | number) => string | number; }'.
  Types of property 'add' are incompatible.
    Type '(value: { num: number; }) => number' is not assignable to type '(value: string | number) => string | number'.
      Types of parameters 'value' and 'value' are incompatible.
        Type 'string | number' is not assignable to type '{ num: number; }'.
          Type 'string' is not assignable to type '{ num: number; }'.(2345) */

c不是兼容的对象类型,但如果您已将其包含在原始约束中,则允许:
TSPlayground

class C {
  add (value: { num: number }): { num: number } {
    return { num: 10 + value.num };
  }
}

function runObejctMethod <T extends Parameters<(A | B | C)['add']>[0]>(
  //                                                    ^
  //                                     C is now included in the union
  obj: { add: (value: T) => T },
  value: T,
): void {
  const result = obj.add(value);
  console.log(result);
}

const c = new C();
runObejctMethod(c, { num: 1 }); // Ok

相关问题