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

velaa5lx  于 2023-01-14  发布在  TypeScript
关注(0)|答案(2)|浏览(131)
function f<T>(defaultValue?: T) { return defaultValue; }

const definitelyUndefined = f<string>();      // type: string | undefined
const definitelyString = f<string>('foobar'); // type: string | undefined

是否可以定义f(),使得definitelyUndefined隐式为undefineddefinitelyString隐式为string
背景
我的真实的用例是一个我正在使用并希望改进的函数。它是function f<T>(o: { [key: string]: T }, key: string, defaultValue?: T),如果它存在,它将返回key[o],否则返回defaultValue。当我向它提供defaultValue时,我保证会返回T,但Typescript认为它是T | undefined

j1dl9f46

j1dl9f461#

对于您的第一个案例,我立即想到了使用重载,例如:

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

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

46scxncf

46scxncf2#

可接受的答案将“类型空间”和“值空间”合并(正如其中一条注解所述)。
这是次优的。这里有一个替代方案:

** typescript 〉= 4.7.4**

// Type definition
type ValueElseUndefined<T> =
  T extends (string | number | boolean | symbol | object) ? T : undefined;

// Function definition
function f<T>(defaultValue?: T): ValueElseUndefined<T> {
  return defaultValue as any;
}

// Invocations
const definitelyUndefined = f();      // type: undefined
const definitelyString = f('foobar'); // type: string

** typescript 〈4.7.4**

// Type definition
type ValueElseUndefined<T> =
  T extends (string | number | boolean | symbol | object) ? T : undefined;

// Function definition
function f<T>(defaultValue?: T): ValueElseUndefined<typeof defaultValue> {
  return defaultValue as any;
}

// Invocations
const definitelyUndefined = f();      // type: undefined
const definitelyString = f('foobar'); // type: string

相关问题