简体   繁体   English

打字稿:类型“{}”不能指定为“选择”类型 <T, K> &#39;,如何正确输入javascript`pick`功能?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM