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

时间:2019-03-24 20:44:29

标签: typescript

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

2 个答案:

答案 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