Reputation: 155
Here is how I played with some advanced types. I want to make a config type that extends BaseConfig. With this config type, inter to a dataProducer type (Named as Conf in the example) that has the same property that is marked as 'yes' in the config type.
interface BaseConfig1 {
a: 'yes'|'no';
b: 'yes'|'no';
}
interface BaseConfig2 {
a?: 'yes';
b?: 'yes';
}
interface Config1 extends BaseConfig1 {
a: 'yes';
}
interface Config2 extends BaseConfig2 {
a: 'yes';
}
type Conf<T, D> = {
[P in keyof T]: T[P] extends 'yes'? ((data:D) => string): never;
};
// Error. Missing property b.
const dataProducer1: Conf<Config1, any> = {a: (data:any) => ''};
// Works
const dataProducer2: Conf<Config2, any> = {a: (data:any) => ''};
Ideally, BaseConfig1 is what I actually want to define. You need to mark 'Yes' in the child type to config the output type. But TS insist me to provide a b property whose type is never. Aren't never supposed to be left out in the types just like the Filter type?
type Filter<T, U> = T extends U ? T : never;
The best I can do is BaseConfig2, any better ideas?
Update: I do want to force the result type to have properties marked as 'yes' type. For the above example, the result type should have "a" property.
Update2: Another question, for BaseConfig2, b's type is 'yes'|undefined, so why the Conf<Config2, any>
would expect a optional b property with undefined type instead of a b with never type.
Update3: Tried a different way to define Conf, but doesn't work.
type Conf<T, D> = {
[P in keyof T & T[P] extends 'yes']: (data:D) => string;
};
Upvotes: 0
Views: 933
Reputation: 2358
interface BaseConfig {
a: 'yes'|'no';
b: 'yes'|'no';
}
interface BaseConfigD {
a: (data:any) => string;
b: (data:any) => string;
}
interface Config extends BaseConfig {
a: 'yes';
}
// Extract the property names that extend 'yes'
type ConfProps<T> = {
[P in keyof T]: T[P] extends 'yes'? P: never;
}[keyof T];
// Properties of Config that extend 'yes'
type ConfigProps = ConfProps<Config>;
// Properties of BaseConfigD that extend 'yes' from Config..
type BaseConfigDBasedOnConfigProps = Pick<BaseConfigD, ConfigProps>;
const dataProducer1: BaseConfigDBasedOnConfigProps = {a: (data:any) => ''};
Upvotes: 1