[英]Typescript: Type '{}' is not assignable to type 'Pick<T, K>', how do I type javascript `pick` function correctly?
I want to type a function called pick
, I know typescript has built-in Pick<T, K>
, now I want to implement the actual source code usage part, but I'm stuck. 我想输入一个名为
pick
的函数,我知道typescript有内置的Pick<T, K>
,现在我想实现实际的源代码使用部分,但是我被卡住了。
What this function do is to pick
provided object
's property based on given strings and return new object
. 这个函数的作用是根据给定的字符串
pick
提供的object
的属性并返回new object
。
The usage is this: 用法是这样的:
const data = { name: 'Jason', age: 18, isMember: true };
const pickedData = pick(data, ['name', 'isMember']);
console.log(pickedData)
// => { name: 'Jason', isMember: true }
My pick
function's javascript implementation without typescript
is this: 我的
pick
函数without typescript
的javascript实现是这样的:
function pick(obj, properties) {
let result = {}
properties.forEach(property => {
result[property] = obj[property];
});
return result;
}
Here is the typescript
version, but it's not compiling: 这是
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;
}
My VSCode screenshot: 我的VSCode截图:
But, there is one solution, I don't know if this is a good
solution, that is to add as Pick<T, K>
: 但是,有一个解决方案,我不知道这是否是一个
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;
}
However, when using this pick
function, typescript
doesn't show the picked object property, instead, it shows unnecessary information: 但是,使用此
pick
函数时, typescript
不会显示拾取的对象属性,而是显示不必要的信息:
It shows me this: 它告诉我这个:
// typescript shows me, not what I want.
const pickedData: Pick<{
name: string;
age: number;
isMember: boolean;
}, "name" | "isMember">
Is there any way that typescript
can show me this? typescript
有什么方法可以告诉我这个吗?
// This is what I want typescript to show me.
const pickedData: {
name: string;
isMember: boolean;
}
The first problem is that {}
should not be assignable to Pick<T, K>
since Pick<T, K>
will probably have required properties. 第一个问题是
{}
不能分配给Pick<T, K>
因为Pick<T, K>
可能具有必需的属性。 There are some instances where a type assertion is the only way to get things to work and this is one of those. 在某些情况下,类型断言是使事情发挥作用的唯一方法,这就是其中之一。 Typescript does not know that you plan to assign those properties a bit later, you have that information and provide it to the compiler in the form of the type assertion, basically saying, relax, I know this isn't really
Pick<T, K>
but I will make it into that shortly. Typescript不知道你计划稍后分配这些属性,你有那些信息,并以类型断言的形式提供给编译器,基本上说,放松,我知道这不是真的
Pick<T, K>
但我很快就会明白这一点。
The second part of you issue is not so much a functional one Pick<{ name: string; age: number; isMember: boolean;, "name" | "isMember">
问题的第二部分不是功能性的
Pick<{ name: string; age: number; isMember: boolean;, "name" | "isMember">
Pick<{ name: string; age: number; isMember: boolean;, "name" | "isMember">
Pick<{ name: string; age: number; isMember: boolean;, "name" | "isMember">
is structurally equivalent to { name: string; isMember: boolean; }
Pick<{ name: string; age: number; isMember: boolean;, "name" | "isMember">
在结构上等同于{ name: string; isMember: boolean; }
{ name: string; isMember: boolean; }
{ name: string; isMember: boolean; }
. { name: string; isMember: boolean; }
。 Sometimes the language service expands these types, sometimes it does not. 有时,语言服务会扩展这些类型,有时则不会。 This is a recent issue describing this exact behavior.
这是描述这种确切行为的最新问题 。
You can force an expansion of the type with a more complicated type (an identity mapped type in an intersection with {}
): 您可以使用更复杂的类型(与
{}
的交集中的标识映射类型)强制扩展类型:
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)
Just as a warning, there are no guarantees Id
will always be expanded, all I can say is that in the current version Id
seems to always force the expansion of the mapped type. 就像一个警告,没有保证
Id
将永远被扩展,我只能说在当前版本Id
似乎总是强制扩展映射类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.