我想键入一个名为pick
的函数,我知道typescript内置Pick<T, K>
,现在我想实现实际的源代码用法部分,但是我遇到了麻烦。
此功能的作用是pick
根据给定的字符串提供object
的属性,并返回new object
。
用法是这样
const data = { name: 'Jason', age: 18, isMember: true };
const pickedData = pick(data, ['name', 'isMember']);
console.log(pickedData)
// => { name: 'Jason', isMember: true }
我的pick
函数的javascript实现without typescript
是这样的:
function pick(obj, properties) {
let result = {}
properties.forEach(property => {
result[property] = obj[property];
});
return result;
}
这里是typescript
版本,但尚未编译:
function pick<T, K extends keyof T>(obj: T, properties: K[]): Pick<T, K> {
let result: Pick<T, K> = {}; // Typescript yells: Type '{}' is not assignable to type 'Pick<T, K>'.
properties.forEach(property => {
result[property] = obj[property];
});
return result;
}
我的VSCode屏幕截图:
但是,有一个解决方案,我不知道这是否是good
解决方案,那就是添加as Pick<T, K>
:
function pick<T, K extends keyof T>(obj: T, properties: K[]): Pick<T, K> {
let result: Pick<T, K> = {} as Pick<T, K> ; // Typescript now satisfy with this.
properties.forEach(property => {
result[property] = obj[property];
});
return result;
}
但是,在使用此pick
函数时,typescript
不会显示所选择的对象属性,而是会显示不必要的信息:
它向我展示了这一点:
// typescript shows me, not what I want.
const pickedData: Pick<{
name: string;
age: number;
isMember: boolean;
}, "name" | "isMember">
typescript
可以通过任何方式向我显示吗?
// This is what I want typescript to show me.
const pickedData: {
name: string;
isMember: boolean;
}
答案 0 :(得分:3)
第一个问题是{}
不可分配给Pick<T, K>
,因为Pick<T, K>
可能具有必需的属性。在某些情况下,类型断言是使事情正常运行的唯一方法,而这就是其中之一。 Typescript不知道您打算稍后再分配这些属性,您拥有该信息并将其以类型断言的形式提供给编译器,基本上是说,放松一下,我知道这并不是真的Pick<T, K>
但我很快会讲到。
问题的第二部分不是功能性的Pick<{ name: string; age: number; isMember: boolean;, "name" | "isMember">
,在结构上等同于{ name: string; isMember: boolean; }
。有时语言服务会扩展这些类型,有时则不会。这是最近的issue,描述了这种确切行为。
您可以使用更复杂的类型(与{}
相交的身份映射类型)来强制扩展类型:
type Id<T extends object> = {} & { [P in keyof T]: T[P] }
function pick<T, K extends keyof T>(obj: T, properties: K[]): Id<Pick<T, K>> {
let result: Pick<T, K> = {} as Pick<T, K> ; // Typescript now satisfy with this.
properties.forEach(property => {
result[property] = obj[property];
});
return result;
}
const data = { name: 'Jason', age: 18, isMember: true };
const pickedData = pick(data, ['name', 'isMember']);
console.log(pickedData)
仅作为警告,没有保证Id
将始终被扩展,我只能说,在当前版本Id
中似乎总是强制扩展映射类型。