Typescript无法检查函数类型和对象类型的并集中的属性

时间:2018-12-08 20:35:56

标签: typescript

Typescript无法检查在函数类型和对象类型的联合中被其他对象和函数的联合截取的属性。

这是用于重现此问题的最小回购协议。存档的正确方法是什么?

type Component = () => {};
type OneType =
  | Component
  | { component: Component }
  | { getComponent: () => Component }

type AnotherType =
  | Component
  | ({ // static properties of Component
    option?: string;
    anotherOption?: string;
  } & OneType);

type AnyObject = {
  [name: string]: AnotherType
}

function aFunction(comps: AnyObject, name: string) {
  const comp = comps[name];

  // [ts] fail here: Property 'component' does not exist on type 'AnotherType'
  if (comp.component) {
    return comp.component;
  }

  // [ts] fail here: Property 'getComponent' does not exist on type 'AnotherType'
  if (typeof comp.getComponent === 'function') {
    return comp.getComponent();
  }

  return comp;
}

这是游戏世界:Playground repo

1 个答案:

答案 0 :(得分:2)

Typescript仅允许您访问联合中的公共属性。一种解决方案是使用in类型防护来说服编译器您正在谈论的是哪个联盟成员。

type Component = () => {};
type OneType =
  | Component
  | { component: Component }
  | { getComponent: () => Component }

type AnotherType =
  | Component
  | ({ // static properties of Component
    option?: string;
    anotherOption?: string;
  } & OneType);

type AnyObject = {
  [name: string]: AnotherType
}

function aFunction(comps: AnyObject, name: string) {
  const comp = comps[name];

  // ok
  if ('component' in comp) {
    return comp.component;
  }

  // ok
  if ('getComponent' in comp && typeof comp.getComponent === 'function') {
    return comp.getComponent();
  }

  return comp;
}

在3.2中,如果启用了null检查,则还可以在联合的所有成员上声明缺少的属性,但是如果类型为undefined,则将它们声明为可选。这将使您能够访问并集上的属性,并且由于它们的类型不重叠,因此Typescript会将其视为已区分的并集,并且在检查属性时会缩小预期的类型。

type Component = () => {};
type OneType =
  | (Component & { component?: undefined, getComponent?: undefined})
  | { component: Component }
  | { getComponent: () => Component, component?: undefined}

type AnotherType =
  | (Component & { component?: undefined, getComponent?: undefined})
  | ({ // static properties of Component
    option?: string;
    anotherOption?: string;
  } & OneType);

type AnyObject = {
  [name: string]: AnotherType
}

function aFunction(comps: AnyObject, name: string) {
  const comp = comps[name];
{
  if (comp.component) {
    return comp.component;
  }

  if (typeof comp.getComponent === 'function') {
    return comp.getComponent();
  }

  return comp;
}