I need to make this logic work.
const defaultNumberOption = {
label: 'Select',
value: 0,
};
const defaultStringOption = {
label: 'Select',
value: '',
};
const getDefaultOption = <ValueType extends string | number>(): IOption => {
// if ValueType is 'string' - return defaultStringOption
// if ValueType is 'number' - return defaultNumberOption
}
I tried to use different approaches, but with each of them had the same problem: I can't find a way to make a structure with types in condition, but with values in expression.
If there is a way to do it - it would be great.
CodePudding user response:
enum FixedLabel {Select}
const defaultNumberOption = {
label: FixedLabel.Select,
value: 0,
};
const defaultStringOption = {
label: FixedLabel.Select,
value: '',
};
type DefaultNumber = { label: FixedLabel, value: number};
type DefaultString = { label: FixedLabel, value: string};
type IOption = DefaultNumber | DefaultString;
const getDefaultOption = (v : number | string): IOption => {
// if ValueType is 'string' - return defaultStringOption
// if ValueType is 'number' - return defaultNumberOption
if(typeof v === 'string'){
return defaultNumberOption;
} else {
return defaultStringOption;
}
}
You can try this might work for you can also use string instead of enum if you are not sepcific to labels.
CodePudding user response:
You could use conditional types to achieve this.
interface DefaultNumberOption {
label: 'Select',
value: number,
}
interface DefaultStringOption {
label: 'Select',
value: string,
}
type DefaultOption<T extends number | string> = T extends string
? DefaultStringOption
: DefaultNumberOption
const getDefaultOption = <T extends number | string>(value: T): DefaultOption<T> => {
if (typeof value === 'string') {
return {
label: 'Select',
value: ''
} as DefaultOption<T>;
}
return {
label: 'Select',
value: 0
} as DefaultOption<T>;
}
let x = getDefaultOption(''); // x will have type DefaultStringOption
let y = getDefaultOption(0); // y will have type DefaultNumberOption
Here is a link to a TS playground if you want to play around with the solution.
CodePudding user response:
TypeScript loses the typing information provided in <T extends string | number>
when building to JS, which is why it does not allow you to use that.
In order to obtain the type, you may want to provide it as a parameter in the function.
const getDefaultOption = <T extends string | number>(optionValue: T): IOption => {
return typeof optionValue === "string" ? defaultStringOption : defaultNumberOption;
}
It is also possible to add it to the return type instead:
const getDefaultOption = <T extends string | number>(getOptionType: T): IOption<string | number> => {
if (typeof getOptionType === "string") return defaultStringOption;
else return defaultNumberOption;
}
Note that IOption cannot contain <T>
as TS would require the return type to be string | number
instead of string
or number
.
Here's my TS playground