我有一个TypScript类Foo
,其中包含fieldOne: number | string
和fieldTwo
,当fieldOne
是number
时,它们将属于Bar[]
类型,当fieldOne
是string
时,它们将属于Baz[]
类型.这两个字段都作为构造函数参数提供.
类中的大部分功能都基于Bar
和Baz
的联合,但在一个地方,我需要将类型缩小为Bar
或Baz
.有没有一种方法可以使用编译器来强制Foo
只能用number
和Bar[]
或string
和Baz[]
实例化.那么,在班上需要的时候我可以将fieldTwo
的类型缩小到Bar[]
或Baz[]
吗?
我可以通过继承来达到如here所示的效果.
interface Bar {
foo: string;
bar: number;
}
interface Baz {
foo: string;
baz: number;
}
abstract class Foo<T extends number | string, U extends Bar[] | Baz[]> {
private fieldOne: T;
protected fieldTwo: U;
constructor(paramOne: T, paramTwo: U) {
this.fieldOne = paramOne;
this.fieldTwo = paramTwo;
}
generalFunction() {
console.log(this.fieldTwo.map(x => x.foo).join());
this.specificFunction();
}
protected abstract specificFunction(): void;
}
class FooBar extends Foo<number, Bar[]> {
specificFunction() {
console.log(this.fieldTwo.map(x => x.bar).join());
}
}
class FooBaz extends Foo<string, Baz[]> {
specificFunction() {
console.log(this.fieldTwo.map(x => x.baz).join());
}
}
但我觉得有点冗长.
我希望得到更简洁的条件类型作为here
type FooContents<T extends number | string> = T extends number ? Bar : Baz;
class Foo<T extends number | string> {
private fieldOne: T;
private fieldTwo: FooContents<T>;
constructor(param1: T, param2: FooContents<T>) {
this.fieldOne = param1;
this.fieldTwo = param2;
}
generalFunction() {
console.log(this.fieldTwo.foo);
}
specificFunction() {
// somehow narrow the type, maybe based on this.fieldOne?
// if fieldOne is number do something with Bar[];
// if fieldOne is string do something with Baz[];
}
}
但我无法让它像我需要的那样工作.
第三种方法here将两个字段组合成一个对象.
type FooParams = {one: number, two: Bar[]} | {one: string, two: Baz[]};
class Foo {
params: FooParams;
constructor(params: FooParams) {
this.params = params;
}
generalFunction() {
console.log(this.params.two.map(x => x.foo).join());
}
specificFunction() {
if (isNumberyBary(this.params)) this.processBars(this.params.two);
if (isStringyBazy(this.params)) this.processBazs(this.params.two);
}
processBars(bars: Bar[]) {
console.log(bars.map(x => x.bar).join());
}
processBazs(bazs: Baz[]) {
console.log(bazs.map(x => x.baz).join());
}
}
function isNumberyBary(x: FooParams): x is {one: number, two: Bar[]} {
return typeof x === 'number';
}
function isStringyBazy(x: FooParams): x is {one: string, two: Baz[]} {
return typeof x === 'number';
}
但同样,它比我希望的要冗长.