function f<T>(defaultValue?: T) { return defaultValue; }
const definitelyUndefined = f<string>(); // type: string | undefined
const definitelyString = f<string>('foobar'); // type: string | undefined
是否可以定义f()
使得definitelyUndefined
隐式为undefined
而definitelyString
隐式为string
?
我在现实世界中的用例是我正在使用并且想要改进的功能。它是function f<T>(o: { [key: string]: T }, key: string, defaultValue?: T)
,如果存在则返回key[o]
,否则返回defaultValue
。当我将其提供给defaultValue
时,可以保证会退回T
,但是Typescript会认为它是T | undefined
。
答案 0 :(得分:3)
对于第一种情况,我立即想到使用重载,例如:
function f<T>(): undefined;
function f<T>(value: T): T;
function f<T>(value?: T) { return value; }
const definitelyUndefined = f(); // type: undefined
const definitelyString = f('foobar'); // type: "foobar"
但是,对于更复杂的用例,我认为也许可以通过重载和更复杂的泛型来解决它,例如:
function f<T, K extends string & keyof T>(o: T, key: K, defaultValue?: T[K]): T[K];
function f<T, V = undefined>(o: T, key: string, defaultValue?: V): V;
function f<T, V = undefined>(o: T, key: string, defaultValue?: V) {
return o[key] || defaultValue;
}
const obj = { foo: "123" };
const definitelyUndefined = f(obj, "bar"); // type: undefined
const definitelyNumber = f(obj, "bar", 123); // type: number
const definitelyString = f(obj, "foo"); // type: string
我不知道这是否适用于所有可能的情况(因为返回类型是根据泛型类型参数而不是实际函数参数确定的),但是我认为它已经非常接近了。
答案 1 :(得分:0)
遗憾的是,除了重载之外,没有一流的支持。
这是我迟来的贡献。
// Type definition
type ValueOrUndefined<T> =
T extends (string | number | boolean | symbol | object) ? T : undefined;
// Function definition
function f<T>(defaultValue?: T): ValueOrUndefined<typeof defaultValue> {
return defaultValue as any;
}
// Invocations
const definitelyUndefined = f(); // type: undefined
const definitelyString = f('foobar'); // type: string