可以有一个具有不同值类型的交集类型吗?

时间:2019-12-24 10:01:07

标签: typescript

我正在尝试编写可用于初始化模拟对象的初始化对象类型。我不想定义所有字段,因为我想重用此类型。我定义了这样的自定义类型:

type InitObjType = { [key: string]: string } & { customKey?: Observable<boolean> };

function initializator(obj: InitObjType) {...}

如果我尝试将init对象传递给initializator函数,例如:

const subject = new Subject<boolean>;

initializator({
  a: 'a',
  b: 'b',
  c: 'c',
  customKey: subject,
});

我收到错误:

error TS2345: Argument of type '{ a: string; b: string; c: string; customKey: Observable<boolean>; }' is not assignable to parameter of type 'InitObjType'.
  Type '{ a: string; b: string; c: string; customKey: Observable<boolean>; }' is not assignable to type '{ [key: string]: string; }'.
    Property 'customKey' is incompatible with index signature.
      Type 'Observable<boolean>' is not assignable to type 'string'.

我使用TypeScript 3.5.3。

有什么想法为什么类型交集不起作用?

谢谢!

1 个答案:

答案 0 :(得分:2)

关于索引类型here的解释很好。

声明索引签名基本上意味着所有显式属性也必须符合索引签名。使用交集类型来解决此问题,在声明类型时确实可行-但您将无法创建对象。 github上也对此进行了一些讨论。

使用子类型

将索引签名移动到这样的子类型被认为是最佳实践:

type InitObjType = { 
  customKey?: Observable<boolean>,
  additionalProperties: { [key: string]: string }
};

function initializator(obj: InitObjType) {...}

const subject = new Subject<boolean>;

initializator({
  customKey: subject,
  additionalProperties: {
    a: 'a',
    b: 'b',
    c: 'c',
  }
});

使用较少的类型安全选项

如果绝对必须将附加属性保持在同一级别,则必须使用不太安全的类型。通过更改索引签名:

type InitObjType = { 
  customKey?: Observable<boolean>,
  [key: string]: string | Observable<boolean>
};

// Or even less type-safe with any

type InitObjType = { 
  customKey?: Observable<boolean>,
  [key: string]: any
};

或在创建对象时进行类型转换:

const subject = new Subject<boolean>;

initializator({
  a: 'a',
  b: 'b',
  c: 'c',
  customKey: subject,
} as any);

最后一个示例有一个有趣的副作用。由于TypeScript仅阻止您创建此类型的对象(因此您必须将其强制转换为任何对象),因此您仍然可以将该对象强制返回以再次获得类型安全性(权衡是每次必须键入它)。

const subject = new Subject<boolean>;

initializator({
  a: 'a',
  b: 'b',
  c: 'c',
  customKey: subject,
} as any as InitObjType);