I need a function to return some of "default" values for a type. Say, I want -1 for integers, "none" for strings, MyEnum.DefaultValue for an enum...
I started from the following problem to implement a generic function for the code bellow:
( .value
is of 'string' type that I try to convert to strings, numbers or booleans)
public getPropertyValue<Type>(propertyCode: string, properties: PropertyValue[]): Type {
return <Type>(properties.find(x => x.propertyCode === propertyCode)?.value || defaultValue);
}
public async calculate(properties: PropertyValue[]): Promise<CalculatorResult[]> {
const STA = <EnumSTA>(properties.find(x => x.propertyCode === 'STA')?.value || EnumSTA.NF_EN_1992_1_1_NA);
const FYK = <number>(properties.find(x => x.propertyCode === 'FYK')?.value || 0);
const CON = <EnumCON>(properties.find(x => x.propertyCode === 'CON')?.value || EnumCON.C3037);
const BCO = <number>(properties.find(x => x.propertyCode === 'BCO')?.value || 0);
const HCC = <string>(properties.find(x => x.propertyCode === 'HCC')?.value || 'none');
const GTC = <number>(properties.find(x => x.propertyCode === 'GTC')?.value || 0);
I want to write a generic function that would return me the default type value, like this
Some pseudo code bellow:
public getDefaultValue<Type>(): Type {
switch(typeof (Type)){
case 'boolean': return false;
case 'number': return -1;
case 'string': return "none";
case 'EnumCity': return EnumCity.Paris;
}
}
what closest real variant of that function is possible with Type/Java/Script?
PS.
Suppose I have the full list of possible types, so, I could create something like this, that compiles well in TypeScript:
getPropertyValue<Type extends (string | number | boolean | EnumCity)>()
{
return <Type>(properties.find(x => x.propertyCode === propertyCode)?.value);
}
TypeScript is transpiled into JavaScript, and JavaScript will not know about the T
in getPropertyValue<T>
, since all type annotations are erased from your TS code when it is transpiled into JS.
I'd suggest you rewrite your getPropertyValue
to accept another parameter that will be used as the default value when needed. Much like Java's getOrDefault
convention or Rust's unwrap_or
.
public getPropertyValueOrDefault<ValueType, DefaultType = ValueType>(
propertyCode: string,
properties: PropertyValue[],
defaultValue: DefaultType
): ValueType | DefaultType {
return (
properties.find(
x => x.propertyCode === propertyCode
)?.value as ValueType ?? defaultValue
);
}
Notice that the property.value as ValueType
is a footgun . If I understood your question correctly, property.value
is actually always a string
. Then the only type safe option is to have different getter functions for different types:
public getBooleanPropertyOrDefault(
propertyCode: string,
properties: PropertyValue[],
defaultValue: boolean
): Boolean {
const value = properties.find(x => x.propertyCode === propertyCode);
return typeof value === "undefined" ? defaultValue : Boolean(value);
}
public getNumberPropertyOrDefault(
propertyCode: string,
properties: PropertyValue[],
defaultValue: number
): Number {
const value = properties.find(x => x.propertyCode === propertyCode).value;
return typeof value === "undefined" ? defaultValue : Number(value);
}
// And so on
Or even something like my preferred solution to avoid the cognitive load with long function names:
public getProp(code: string, props: PropertyValue[]) {
const value = props.find(x => x.propertyCode === propertyCode).value;
return {
asBoolOr: (dflt: boolean) => Boolean(value ?? dflt),
asNumberOr: (dflt: number) => Number(value ?? dflt),
asStringOr: (dflt: string) => String(value ?? dflt),
parseOr: <T>(parser: (value: string) => T, dflt: T) =>
typeof value !== "undefined"
? parser(value)
: dflt,
};
}
Which you'd then use as
const STA = getProp("STA", properties)
.parseOr(/* parseSta */, EnumSTA.NF_EN_1992_1_1_NA);
const FYK = getProp("FYK", properties).asNumberOr(0);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.