I have an entry class called BackgroundLayer
. It takes two arguments, (1) the type of the background and (2) the configuration of that background. When (1) is type of Background.Grid
, then the configuration needs to be of type GridBackgroundConfig. When (1) is type of Background.Checkered
the configuration needs to be type of CheckeredBackgroundConfig. What I want is, when typing new BackgroundLayer(Background.Grid
, the configuration (argument 2) needs to be type of GridBackgroundConfig. The source code below is my try, but it allows passing Background.Grid as (1) and an object of type CheckeredBackgroundConfig as (2) which shouldnt be allowed. I tried using multiple constructor implementations (constructor(type: Background.Grid, config: GridBackgroundConfig); constructor(type: BackgroundEnum.Checkered,config: CheckeredBackgroundConfig);
but then I need to create a new constructor for every entry in Background
manually. I wondered if it was possible to narrow the type of the second argument, if the type of the first argument is known.
enum Background {
Grid = "Grid";
Checkered = "Checkered";
}
interface LayerConfig {
/* ... */
}
interface GridBackgroundConfig extends LayerConfig {
/* ... */
}
interface CheckeredBackgroundConfig extends LayerConfig {
/* ... */
}
class Layer {
protected config: LayerConfig;
constructor(config: LayerConfig) {
this.config = config;
}
}
class BackgroundLayer extends Layer {
private background: Background;
constructor(type: Background, config: GridBackgroundConfig | CheckeredBackgroundConfig) {
super(config);
if (type === Background.Grid) {
this.background = new Grid(config as GridbackgroundConfig);
} else if (type === Background.Checkered) {
this.background = new Checkered(config as CheckeredBackgroundConfig);
} else {
throw "check argument types";
}
}
}
class Grid {
private config: GridBackgroundConfig;
constructor(config: GridBackgroundConfig) {
this.config = config;
}
}
class Checkered {
private config: CheckeredBackgroundConfig;
constructor(config: CheckeredBackgroundConfig) {
this.config = config;
}
}
CodePudding user response:
You should probably stick with using overloads here, but anyways, if you define a type that maps background types to their respective configs...
type ConfigMap = {
[Background.Grid]: GridBackgroundConfig;
[Background.Checkered]: CheckeredBackgroundConfig;
};
You should be able to make your class generic and edit the constructor to use the type parameter:
class BackgroundLayer<Type extends Background> extends Layer {
private background: Grid | Checkered;
constructor(type: Type, config: ConfigMap[Type]) {
Then the type of config
depends on what was given to type
.