Reputation: 5335
Example
class BaseOptions {
a: 1;
}
class OptionsA extends BaseOptions {
b: 2;
}
class OptionsB extends BaseOptions {
c: 3;
}
class Child<TOptions extends BaseOptions> {
options: TOptions;
}
// Parent must use a child that supports TOptions
class Parent<TOptions extends BaseOptions, TChild extends Child<TOptions>> { }
// Supports OptionsA
class StrictChild extends Child<OptionsA> { }
// Supports OptionsA and OptionsB
class FlexibleChild extends Child<OptionsA | OptionsB> {
doSomething() {
if (this.options instanceof OptionsA) {
const test1 = this.options.b;
}
// This should fail because no instanceof check
const test2 = this.options.c;
}
}
// Expected to fail because StrictChild can't have OptionsB
const parentA = new Parent<OptionsB, StrictChild>();
// Expected to pass because FlexibleChild can have OptionsA or OptionsB
// but fails because "OptionsA" is not assignable to "OptionsA | OptionsB"
const parentB = new Parent<OptionsB, FlexibleChild>();
I think the problem is
class Parent<TOptions extends BaseOptions, TChild extends Child<TOptions>> { }
specifically Child<TOptions>
because I think it needs to be something like Child<TOptions extends Child<T>>
but I have no idea how to do that.
Upvotes: 2
Views: 125
Reputation: 5335
I think I have it working so long as I set a default generic on Child so that I can use TChild['options']
class Child<TOptions extends BaseOptions = BaseOptions> {
options: TOptions;
}
// Parent must use a child that supports TOptions
class Parent<TOptions extends TChild['options'], TChild extends Child> { }
Edit
Alternatively you can just do
class Parent<TOptions extends TChild['options'], TChild extends Child<BaseOptions>> { }
Upvotes: 1
Reputation: 4815
You are looking for intersection types, not union types!
// Supports OptionsA and OptionsB
class FlexibleChild extends Child<OptionsA & OptionsB> { }
Now this is a perfectly valid statement:
const parentB = new Parent<OptionsB, FlexibleChild>();
Reference: https://www.typescriptlang.org/docs/handbook/advanced-types.html
An intersection type combines multiple types into one. This allows you to add together existing types to get a single type that has all the features you need. For example,
Person & Serializable & Loggable
is aPerson
andSerializable
andLoggable
. That means an object of this type will have all members of all three types.
Upvotes: 0