紧随this great answer to a related question之后,我们得到ObjectDiff
(出于以下目的,我将其重命名为ObjectExclude
)
我有一个接受一个对象的函数,以及一个我想从该对象的克隆中删除的属性列表。我如何告诉Typescript这里发生了什么?该类型应为传入的对象,然后减去其后传入键的属性。
type ObjectExclude<T, U> = Pick<T, Exclude<keyof T, keyof U>>;
function removeProps<T extends object, U extends keyof T>(
obj: T,
...propNames: U[]
): SomeType { // What type should this actually be?
const objClone = { ...obj };
propNames.forEach(p => delete objClone[p]);
return objClone;
}
SomeType
似乎是可以派生的东西,但我总是最终只是进行类型转换。
例如,如何在不进行手动类型转换的情况下告诉打字稿下面的b
是类型{one: number, two: string}
?
const a = {one: 1, two: '2', three: true};
const b = removeProps(a, 'three'); // TS should just know the type here.
将代码看作一个了解JS或TS的人,很明显b
的类型
interface B {one: number; two: string}
我希望TS也知道这一点,而无需告诉它。
答案 0 :(得分:0)
Typescript可以根据您在其余参数中使用的输入字符串为您构造一个对象类型。以下removeProps
的实现与上面的完全相同。仅类型定义已更改。
我们构造Z
类型的唯一目的是将其排除在T
类型之外。
function removeProps<T extends object, K extends keyof T, Z = {[P in K]: any}>(
obj: T,
...propNames: K[]
): ObjectExclude<T, Z> {
const objClone = { ...obj };
propNames.forEach(p => delete objClone[p]);
return objClone;
}
现在在您的代码中(从TS 3.2.2开始,但是我认为这一直可以回溯到2.8),您将获得以下信息:
const a = {one: 1, two: '2', three: true};
const b = removeProps(a, 'three');
// Type for b: Pick<{one: number, two: string, three: boolean}, "one" | "two">
这基本上意味着类型与对象a
相同,但只包含属性"one"
和"two"
。
注意:从技术上讲
Z
的类型为{[P in K]: T[K]}
,但是any
可以在上面工作,因为它从未以任何方式使用:我们只关心属性,而不关心值,的Z
。
@ titian-cernicova-dragomir在下面指出,甚至不需要整个Z
类型。所以说真的,您要做的就是
export function removeProps<T extends object, U extends keyof T>(
obj: T,
...propNames: U[]
): Pick<T, Exclude<keyof T, U>> {
const objClone = { ...obj };
propNames.forEach(p => delete objClone[p]);
return objClone;
}
这只是通过直接使用构成其的类型而放弃了ObjectExclude
类型。
答案 1 :(得分:0)
我相信您可以使用Partial<T>
作为返回类型