【问题标题】:{ foo: null } has no properties in common with type { bar?: null; fnord?: null }{ foo: null } 与 type { bar?: null; 没有共同的属性fnord?: 空 }
【发布时间】:2019-12-10 14:51:53
【问题描述】:

我有一些类型,它们共享共同的道具,但这些道具有不同的对象。我想合并这些子对象,但它没有按我的预期工作。这是我的代码:

interface IFoo { foo: any };
interface IBarFnord { bar?: any; fnord?: any };

type Union = {test: IFoo } & {test: IBarFnord; otherTest?: IBarFnord };

const fails: Union = { test: { foo: null }};
const works: Union = { test: {foo: null, bar: null }};
const alsoWorks: Union = { test: {foo: null, fnord: null }};

对于const fails,我得到了错误:

类型 '{ foo: null; }' 与类型 'IBarFnord' 没有共同的属性。

这是真的。如果联合手段必须在两者中都有属性,那么它是有道理的。

我已经测试过这样做不是作为子道具,它工作正常:

type Union = {test: IFoo & IBarFnord };

const worksNow: Union = { test: { foo: null }};
const stillWorks: Union = { test: {foo: null, bar: null }};

无论如何,我如何告诉 Typescript 我想联合这些东西,但我不希望每个项目总是在联合的两边都有道具?

【问题讨论】:

  • 您使用的是"union"这个词,但您使用的是&,它表示intersection。那些是不同的;你真正想要哪一个?

标签: typescript types union-types


【解决方案1】:

假设您实际上是指“交叉口”而不是“联合”,这看起来像 known issue 其中excess property checking 分别适用于交叉口的每个组成部分,而实际上它应该只适用于整个交叉口.看起来最近有一些 work 已经解决了这个问题,所以也许修复会使其成为即将发布的版本?不确定。

无论如何,作为一种解决方法,我们可以创建自己的类型别名,它可以积极地递归地合并交集类型中的子属性,如下所示:

type SubpropertyMerge<T> = T extends (...args: infer A) => infer R
  ? (...args: SubpropertyMerge<A>) => SubpropertyMerge<R>
  : T extends object ? { [K in keyof T]: SubpropertyMerge<T[K]> } : T;

此类型应将由基元、对象、数组/元组和非泛型函数组成的类型转换为合并任何交集的等效类型:

type Test = {
  a: string;
  b: number[];
  c: {
    d: boolean;
    e: string | { f: number };
  };
  g: [string, number, { h: number }];
  h: () => string;
  i: (x: number) => number;
  j: (x: { foo: string }) => number[];
};
type MergedTest = SubpropertyMerge<Test>; // looks the same

// MutuallyExtends<A, B> is a compile error unless A and B are mutually assignable 
type MutuallyExtends<T extends U, U extends V, V=T> = true;

type TestIsOkay = MutuallyExtends<Test, MergedTest>; // acts the same

它应该适用于您的类型,我已将其重命名为 Intersection

type MergedIntersection = SubpropertyMerge<Intersection>;
type IntersectionIsOkay = MutuallyExtends<Intersection, MergedIntersection>; // acts the same

但现在你的任务应该如你所愿:

const worksNow: MergedIntersection = { test: { foo: null } };

好的,希望对您有所帮助;祝你好运!

Link to code

【讨论】:

  • type Union = SubpropertyMerge&lt;{test: IFoo } &amp; {test: IBarFnord; otherTest?: IBarFnord }&gt; 成功了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-20
  • 1970-01-01
  • 2015-06-02
  • 1970-01-01
  • 2011-12-27
  • 2012-01-25
  • 1970-01-01
相关资源
最近更新 更多