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

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

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

  1. class A {
  2. add(a: number) {
  3. return 10 + a
  4. }
  5. }
  6. class B {
  7. add(a: string) {
  8. return 'ten' + a
  9. }
  10. }

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

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

错误:

  1. 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方法,您可以使用型别保护来检查对象的型别,然后呼叫适当的方法。
以下是如何实现此函数的示例:

  1. class A {
  2. add(a: number) {
  3. return 10 + a;
  4. }
  5. }
  6. class B {
  7. add(a: string) {
  8. return "ten" + a;
  9. }
  10. }
  11. function runAdd(obj: A | B, value: any) {
  12. if (obj instanceof A || ) {
  13. return obj.add(value);
  14. } else if (obj instanceof B) {
  15. return obj.add(value);
  16. }
  17. }
  18. const a = new A();
  19. const b = new B();
  20. console.log(runAdd(a, 5)); // Output: 15
  21. console.log(runAdd(b, "hello")); // Output: "tenhello"

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

展开查看全部
zbsbpyhn

zbsbpyhn2#

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

  1. const runObejctMethod = (obj: A | B, value: string | number) => {
  2. if (typeof obj === 'A') {
  3. obj.add(value as number);
  4. } else {
  5. obj.add(value as string);
  6. }
  7. }

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

  1. class A {
  2. isA = true;
  3. add(a: number) {
  4. return 10 + a
  5. }
  6. }
  7. class B {
  8. add(a: string) {
  9. return 'ten' + a
  10. }
  11. }
  12. const runObejctMethod = (obj: A | B, value: string | number) => {
  13. if (obj.isA) {
  14. obj.add(value as number);
  15. } else {
  16. obj.add(value as string);
  17. }
  18. }

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

展开查看全部
8hhllhi2

8hhllhi23#

您可以使用泛型

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

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

plupiseo

plupiseo4#

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

  1. class A {
  2. add (value: number): number {
  3. return 10 + value;
  4. }
  5. }
  6. class B {
  7. add (value: string): string {
  8. return 'ten' + value;
  9. }
  10. }
  11. class C {
  12. add (value: { num: number }): { num: number } {
  13. return { num: 10 + value.num };
  14. }
  15. }
  16. function runObejctMethod <T extends Parameters<(A | B)['add']>[0]>(
  17. obj: { add: (value: T) => T },
  18. value: T,
  19. ): void {
  20. const result = obj.add(value);
  21. console.log(result);
  22. }
  23. // The constraint expression above "Parameters<(A | B)['add']>[0]" means:
  24. // "a union of the type of the first parameter of A.add or B.add",
  25. // so — in this case — it means "string | number":
  26. type Constraint = Parameters<(A | B)['add']>[0];
  27. //^? type Constraint = string | number
  28. // You could add more compatible classes to the union
  29. // to extend the accepted types in the constraint,
  30. // for example: Parameters<(A | B | C | D)['add']>[0]
  31. // --------------------
  32. // Usage:
  33. const a = new A();
  34. const b = new B();
  35. const c = new C();
  36. // Ok:
  37. runObejctMethod(a, 1); //=> Logs: 11
  38. runObejctMethod(b, ' thousand'); //=> Logs: "ten thousand"
  39. // Not ok (as expected):
  40. runObejctMethod(a, ' thousand'); /*
  41. ~~~~~~~~~~~
  42. Argument of type 'string' is not assignable to parameter of type 'number'.(2345) */
  43. runObejctMethod(b, 1); /*
  44. ~
  45. Argument of type 'number' is not assignable to parameter of type 'string'.(2345) */
  46. runObejctMethod(c, { num: 1 }); /*
  47. ~
  48. Argument of type 'C' is not assignable to parameter of type '{ add: (value: string | number) => string | number; }'.
  49. Types of property 'add' are incompatible.
  50. Type '(value: { num: number; }) => number' is not assignable to type '(value: string | number) => string | number'.
  51. Types of parameters 'value' and 'value' are incompatible.
  52. Type 'string | number' is not assignable to type '{ num: number; }'.
  53. Type 'string' is not assignable to type '{ num: number; }'.(2345) */

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

  1. class C {
  2. add (value: { num: number }): { num: number } {
  3. return { num: 10 + value.num };
  4. }
  5. }
  6. function runObejctMethod <T extends Parameters<(A | B | C)['add']>[0]>(
  7. // ^
  8. // C is now included in the union
  9. obj: { add: (value: T) => T },
  10. value: T,
  11. ): void {
  12. const result = obj.add(value);
  13. console.log(result);
  14. }
  15. const c = new C();
  16. runObejctMethod(c, { num: 1 }); // Ok
展开查看全部

相关问题