typescript 在引发错误的方法中使用类型脚本联合

flmtquvp  于 2023-03-13  发布在  TypeScript
关注(0)|答案(2)|浏览(116)

我是相对较新的 typescript ,并有什么我认为是一个奇怪的错误。
我有多个对象使用send data到服务器,然后从服务器返回同一对象的新数据。不同的对象使用相同的方法发送数据,所以我使用union来指定方法可以接受这两种类型中的任何一种,但是我得到了一个错误。
我已经制作了一个简单版本的代码来复制这个问题,我可以做到。

type A = {
  aField: string;
  aaField: string;
}

type B = {
  bField: string;
  bbField: number
}

type Student = A | B;

type Func = (student: Student) => Student;

const test = {
  aField: 'Test',
  aaField: 'Test Again'
}

const funcA = (a: A): A => {
  return a;
}
const funcB = (b: B): B => {
  return b;
}

const func = (student: Student): Student => {
  return student;
}

const component = (func: Func) => {
  return func;
}

component(func);

component(funcA);

我得到的错误如下
类型'(a:A)=〉A'不能赋值给' Func'类型的参数。
参数“a”和“student”的类型不兼容。
类型“Student”不能赋值给类型“A”。
类型“B”缺少类型“A”的以下属性:a字段,aa字段
有没有一种方法可以绕过这个问题,而不必强制转换每个函数的类型?

af7jpaap

af7jpaap1#

可以使用分布条件类型将Student联合分布到匹配的函数签名上:

type Func<S = Student> = S extends Student ? (student: S) => S : never;

component(func); // OK
component(funcA); // OK
component(funcB); // OK

这里有一个完整的片段操场链接。

rqqzpn5f

rqqzpn5f2#

当用于输入 callback 参数(如component函数的func参数)时,联合类型的约束比您想象的要大。
当我们有:

type Student = A | B;
type Func = (student: Student) => Student;

......我们说Func * 必须 * 接受Student类型的参数,它可以是(在 * 调用者意愿 * 下)AB
这就是你的func函数所做的,但 * 不是 * funcAfuncB,如果我们尝试将它们输入为Func,就可以看到这一点:

// Error: Type '(a: A) => A' is not assignable to type 'Func'.
const funcA: Func = (a: A): A => {
  //  ~~~~~
  return a;
}

// Error: Type '(b: B) => B' is not assignable to type 'Func'.
const funcB: Func = (b: B): B => {
  //  ~~~~~
  return b;
}

// Okay
const func: Func = (student: Student): Student => {
  return student;
}

Playground链接
funcAfuncB分别接受AB,但不接受并集A | BfuncA不接受B,反之亦然),因此它们不匹配Func
我有多个对象,它们使用向服务器发送数据,然后从服务器返回同一对象的新数据。
根据您的描述,您更需要一个generic类型参数,它也为回调返回提供相同的类型:

const component2b = <T extends A | B>(func: (student: T) => T) => {
  return func;
}

component2b(funcA); // Okay
component2b(funcB); // Okay

对于T extends A | B泛型类型,我们假设func回调函数必须接受T类型的参数,该参数可 * 赋值 * 给A | B,因此AB都可以(不一定同时)。
此外,我们还指定T为返回类型,因此如果传递的回调函数接受A,它也会返回A类型(对于B也是如此),与您的描述相匹配。
Playground链接

相关问题