1

我正在尝试在 typescript 中创建一个函数,其中第二个可选参数是第一个参数的键。没有可选参数,我想要的函数看起来像

function getVal<T>(obj: T, key: keyof T) {
    return obj[key];
}

但是,我想key是可选的,并采用默认值"id". 但是,函数

function getValBad<T>(obj: T, key: keyof T = "id") {
    return obj[key];
}

不进行类型检查,因为打字稿不知道是否Tid. 解决此问题的部分方法是编写

function getValOk<T extends { id: any }>(obj: T, key: keyof T = "id") {
    return obj[key];
}

然而,这股力量T总是有一把钥匙的id

我的问题是,我可以编写一个函数getValGood来进行类型检查getValGood({id: 1})、类型检查getValGood({ID: 1}, "ID")并且getValGood({ID: 1})不进行类型检查。如果是这样,我如何getValGood在打字稿中表示?

4

2 回答 2

1

首先,您可能希望使用另一个通用参数来正确键入返回值。(否则,obj[key]将返回对象上所有可能值的联合,而不仅仅是at 的类型key

您可以重载该getVal函数以获取一个对象和一个作为该对象属性的键(2 个泛型),或者仅使用一个泛型{ id: V }并返回 V 类型的内容:

type GetVal = {
    <T, K extends keyof T>(obj: T, key: K): T[K];
    <V>(obj: { id: V }): V;
};

const getVal: GetVal = (obj: Record<string, unknown>, key = 'id') => {
    return obj[key];
};

const result1 = getVal({ foo: 'foo' }, 'foo');
const result2 = getVal({ foo: 'foo' }, 'doesntexist'); // Fails

const result3 = getVal({ id: 'val' });
const result4 = getVal({ }); // Fails

演示

于 2021-03-18T02:31:05.337 回答
0

我认为你应该为此使用函数重载:

function getVal<V>(obj: {id: V}): V;
function getVal<T, K extends keyof T>(obj: T, key: K): T[K];

function getVal(obj: any, key = 'id') {
    return obj[key];
}

请注意,当函数具有重载签名时,Typescript 不会单独检查函数实现是否真正符合每个重载签名;根据重载签名确保您编写的实现是类型安全的,这取决于您。

Typescript 至少仍会确保对函数的每次调用都是正确键入的。

游乐场链接

于 2021-03-18T02:37:54.170 回答