简体   繁体   English

unionType 不能为 generics Function Typescript 中的参数

[英]unionType cannot be generics Function Parameter in Typescript

I've defined a generics Function, and I'm trying to pass the union of two specific sample of the generics to the function, like I've defined a generics Function, and I'm trying to pass the union of two specific sample of the generics to the function, like

function myCommonFunc<T>({
  data,
  render,
}: {
  data: T;
  render: (data: T) => number;
}) {
  return render(data);
}

interface TestX<T> {
  data: T;
  render: (data: T) => number;
}

let z: TestX<number> | TestX<string>;
// let z: TestX<number | string>  is wrong, because T will be number | string


if ((window as any).someUserInput === 1) {
  z = { data: 1, render: (a: number) => 1 };
} else {
  z = { data: '1', render: (a: string) => 1 };
}

// someother function

myCommonFunc(z);

and it throw errs.它会出错。

I guess the reason is the function cannnot infer type from the unionType, and If so, what should I do?我猜原因是 function 无法从 unionType 推断类型,如果是这样,我该怎么办?

I know one solution is to use typeguard of z, like我知道一种解决方案是使用 z 的 typeguard,例如

function isTypeA(z: TestX<number> | TestX<string>): z is TestX<number> {
  return typeof z.data === 'number';
}
if (isTypeA(z)) {
  myCommonFunc(z);
}

but I think it actually change the structure of the program, and it need lots if-else to just for typescript, which is annoying.但我认为它实际上改变了程序的结构,并且它需要很多 if-else 才能仅用于 typescript,这很烦人。 Can someone give me some other way to solve it?有人可以给我一些其他方法来解决它吗?

This is a hard one.这是一个很难的。 I see 3 solutions:我看到了 3 个解决方案:

Solution 1解决方案 1

Solution 1 is the one you've mentioned above of using type guards:解决方案 1 是您上面提到的使用类型保护的解决方案:

const isTestNumber = (z: TestX<number> | TestX<string>): z is TestX<number> => {
  return typeof z.data === "number"
}

if (isTestNumber(z)) {
  myCommonFunc(z);
} else {
  myCommonFunc(z);
}

It is by far my least favorite solution.这是迄今为止我最不喜欢的解决方案。

Solution 2解决方案 2

Solution 2 is to cast z before passing it as a parameter.解决方案 2 是在将z作为参数传递之前对其进行强制转换。 It looks like this:它看起来像这样:

myCommonFunc(z as TestX<any>); // ugly casting

I know it's ugly , but it's not particularly dangerous since the z variable is fully typed above.我知道这很丑陋,但它并不是特别危险,因为z变量在上面是完全输入的。 At least it does not alter the execution of the program.至少它不会改变程序的执行。

Solution 3解决方案 3

Solution 3 requires some structural change to your program.解决方案 3 需要对您的程序进行一些结构更改。

What you currently do is you declare the z variable, you assign it in an if-else statement and then you perform operations on it afterward.您当前所做的是声明z变量,在if-else语句中分配它,然后对它执行操作。

What you could do is wrap all subsequent operations in another generic function.您可以做的是将所有后续操作包装在另一个通用 function 中。

It looks like this:它看起来像这样:

interface TestX<T> {
  data: T;
  render: (data: T) => number;
}

function myCommonFunc<T>(z: TestX<T>) {
  const { data, render } = z
  return render(data);
}

function allSubsequentOperations<T>(z: TestX<T>) {
  // someother function
  
  myCommonFunc(z);
}

if ((window as any).someUserInput === 1) {
  const z: TestX<number> = { data: 1, render: (a: number) => 1 };
  allSubsequentOperations(z)
} else {
  const z: TestX<string> = { data: "1", render: (a: string) => 1 };
  allSubsequentOperations(z)
}

This is what I usually do when dealing with this kind of problem.这是我在处理此类问题时通常会做的事情。 From the moment z is assigned, your whole program becomes generic.从分配z的那一刻起,您的整个程序就变得通用了。

I hope you find these answers helpful,我希望这些答案对您有所帮助,

François弗朗索瓦

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM