I want to set a default value defVal
based on the type of the incoming variable val
. Many times the val
will be undefined, so I can not use the JavaScript typeof
operator. So T
remains the only source of the type information. Of course the problem is that T
is not known at runtime.
The defVal
should be for example "" for string, 0 for number, etc...
Like defVal = T is string ? "" : 0
function getValue<T>(val?: T): T
{
const defVal = "FIXME" as unknown as T // <---- get default value based on T
return val ?? defVal;
}
const s = getValue<string>(); // want s === ""
const n = getValue<number>(2); // want n === 2
CodePudding user response:
Based on my own experience and the comment from @MikeS., I think that although the Typescript is great for many many things, this is the simple case that it can not add any useful value to the code, because it does not preserve the type information in the runtime.
So it is more useful to use "old school" approach with separately named methods.
function getValueString(val?: string): string
{
return val ?? "";
}
function getValueNumber(val?: number): number
{
return val ?? 0
}
const s = getValueString();
const n = getValueNumber(2);
console.log(s, n);
CodePudding user response:
TypeScript only exists at compile-time, so types can't be used to influence the runtime value that a function will return.
You can modify your function to use an overload signature, so that you can either infer from a value's type, or request a default type of value (taken from an object that you create). Here's an example of how to do that:
const defaults = {
array: [] as unknown[],
bigint: 0n,
boolean: false,
null: null,
number: 0,
object: {} as Record<PropertyKey, unknown>,
string: '',
undefined: undefined,
};
function getValue <T>(typeWanted: 'infer'): undefined;
function getValue <T>(typeWanted: 'infer', value: T): T;
function getValue <T extends keyof typeof defaults>(typeWanted: T): typeof defaults[T];
function getValue <T>(typeWanted: keyof typeof defaults | 'infer', value?: T) {
if (typeWanted === 'infer') return value;
return defaults[typeWanted];
}
console.log(getValue('array')); // unknown[]: []
console.log(getValue('bigint')); // bigint: 0n
console.log(getValue('boolean')); // boolean: false
console.log(getValue('null')); // null: null
console.log(getValue('number')); // number: 0
console.log(getValue('object')); // Record<PropertyKey, unknown>: {}
console.log(getValue('string')); // string: ""
console.log(getValue('undefined')); // undefined: undefined
console.log(getValue('infer')); // undefined
console.log(getValue('infer', 2)); // 2
console.log(getValue('infer', 'hello')); // "hello"
console.log(getValue('infer', ['hello', 'world'])); // string[]: ["hello", "world"]
console.log(getValue('infer', ['hello', 'world'] as const)); // readonly ["hello", "world"]: ["hello", "world"]
// ...etc.