{foo:null}没有类型{bar?:null;fnord?:null}



我有一些类型,这些类型具有共同的道具,但对于这些道具有不同的对象。我想结合那些子对象,但这并不奏效我期望。这是我的代码:

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 }};

无论如何,我怎么能告诉我要结合这些东西的打字稿,但是我不希望每个项目在联盟的两边都有道具?

假设您实际上是指"交叉"而不是"联合",这看起来像是一个已知的问题,在该问题中,多余的属性检查分别适用于相交的每个组成部分到整个交叉点。看来最近已经做了一些解决此问题的工作,所以也许修复程序将使它成为即将发布的版本?不确定。

无论如何,作为解决方法,我们可以制作自己的类型别名,这些别名会积极地和递归地合并相交类型中的子专业,例如:

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 } };

好吧,希望有帮助;祝你好运!

链接到代码

最新更新