根据可选参数指定返回类型

Mar*_*ark 2 typescript

function f<T>(defaultValue?: T) { return defaultValue; }

const definitelyUndefined = f<string>();      // type: string | undefined
const definitelyString = f<string>('foobar'); // type: string | undefined
Run Code Online (Sandbox Code Playgroud)

是否有可能定义f(),使得definitelyUndefined隐式undefineddefinitelyString隐式string

背景

我的真实用例是我正在使用并希望改进的功能。它是function f<T>(o: { [key: string]: T }, key: string, defaultValue?: T)key[o]如果存在则返回,否则返回defaultValue。当我提供它时defaultValue,我保证会T回来,但 Typescript 认为它是T | undefined

p.s*_*w.g 6

对于您的第一种情况,我立即想到使用重载,例如:

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"
Run Code Online (Sandbox Code Playgroud)

但是,对于更复杂的用例,我认为您可以使用重载和更复杂的泛型来解决它,例如:

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
Run Code Online (Sandbox Code Playgroud)

我不知道这是否适用于所有可能的场景(因为返回类型是基于泛型类型参数确定的,而不是实际的函数参数),但我认为它非常接近。

  • @zerkms 已更新,但我对提供的解决方案仍然不是 100% 满意。它仍然将“类型空间”和“值空间”混为一谈,但我不确定是否可以在不对“T”进行更多限制的情况下避免这种情况。 (2认同)