javascript - 打字稿:类型“{}”不可分配给类型“选择”',如何正确输入 javascript `pick` 函数?
问题描述
我想键入一个名为 的函数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;
}
解决方案
第一个问题是{}
不应分配给,Pick<T, K>
因为它Pick<T, K>
可能具有必需的属性。在某些情况下,类型断言是使事情正常工作的唯一方法,这就是其中之一。Typescript 不知道您打算稍后分配这些属性,您拥有该信息并以类型断言的形式将其提供给编译器,基本上是说,放松,我知道这不是真的Pick<T, K>
,但我会做到的很快就进入了。
您问题的第二部分与其说是功能性的,不如说Pick<{ name: string; age: number; isMember: boolean;, "name" | "isMember">
是结构上等同于{ name: string; isMember: boolean; }
. 有时语言服务会扩展这些类型,有时则不会。这是描述这种确切行为的最新问题。
您可以使用更复杂的类型(与 的交集中的标识映射类型{}
)强制扩展类型:
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
似乎总是强制扩展映射类型。
推荐阅读
- swift - 使用 swift grpc 客户端快速的 Google pubsub 客户端?
- xamarin.android - 在 xamarin.android 中管理屏幕旋转时的片段外观
- r - 如何根据第二个值从第一列创建汇总列
- javascript - 如果一个函数返回新的 promise,它是否需要 async 关键字?
- c - unload() 函数的问题(CS50 第 5 周:Speller)
- javascript - 当没有按钮时,如何防止获取请求在 Javascript 中重新加载页面?
- python - 创建新列,该列是按日期计算的一列和另一列的总和
- python - 有没有办法在 Telegram 中实现重定向到机器人/频道?
- databricks - 可以使用 Databricks 社区版生成数据访问令牌吗?
- sql-server - 如何在 SQL Server 的 PIVOT 语句中调用参数