'get generic type in TypeScript [closed]
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);
}
Solution 1:[1]
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 {
or: <T extends string | number | boolean>(dflt: T): T => {
if (typeof value === "undefined") return dflt;
switch(typeof dflt) {
case "string": return String(value);
case "number": return Number(value);
case "boolean": return Boolean(value);
}
},
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).or(0);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
