typescript - 如何在 Typescript 中将默认值设置为具有 keyof 类型(来自显式类型)的参数
问题描述
我在 Typescript 将默认值传递给类似于pick
from lodash的函数时遇到问题。
该函数接受一个已知(非通用)接口的对象和一组键以从该对象中选择和返回。
该函数的常规(无默认参数)声明可以正常工作,但是,我似乎无法将数组设置为选择要选择的属性的参数的默认值。
interface Person {
name: string;
age: number;
address: string;
phone: string;
}
const defaultProps = ['name', 'age'] as const;
function pick<T extends keyof Person>(obj: Person, props: ReadonlyArray<T> = defaultProps): Pick<Person, T> {
return props.reduce((res, prop) => {
res[prop] = obj[prop];
return res;
}, {} as Pick<Person,T>);
}
const testPerson: Person = {
name: 'mitsos',
age: 33,
address: 'GRC',
phone: '000'
};
如果您删除默认值= defaultProps
,它将成功编译,并且返回的类型从示例调用中也是正确的,例如:const testPick = pick(testPerson, ['name']);
但是,设置默认值会产生以下错误:
Type 'readonly ["name", "age"]' is not assignable to type 'readonly T[]'.
Type '"name" | "age"' is not assignable to type 'T'.
'"name" | "age"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'keyof Person'.
Type '"name"' is not assignable to type 'T'.
'"name"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'keyof Person'.
如何成功地将默认值传递给props
参数?
打字稿游乐场链接在这里
更新
在玩了一会儿之后,我尝试使用条件类型并设法使函数签名正常工作,但是现在无法正确识别 reduce 的问题:
interface Person {
name: string;
age: number;
address: string;
phone: string;
}
const defaultProps = ['name', 'age'] as const;
type DefaultProps = typeof defaultProps;
type PropsOrDefault<T extends keyof Person> = DefaultProps | ReadonlyArray<T>;
type PickedPropOrDefault<T extends PropsOrDefault<keyof Person>> = T extends DefaultProps ? Pick<Person, DefaultProps[number]> : Pick<Person, T[number]>;
function pick<T extends keyof Person>(obj: Person, props: PropsOrDefault<T> = defaultProps): PickedPropOrDefault<PropsOrDefault<T>> {
return props.reduce<PickedPropOrDefault<PropsOrDefault<T>>>((res, prop) => {
res[prop] = obj[prop];
return res;
}, {} as PickedPropOrDefault<PropsOrDefault<T>>);
}
const testPerson: Person = {
name: 'mitsos',
age: 33,
address: 'GRC',
phone: '000'
};
const result = pick(testPerson) // Pick<Person, "name" | "age">
const result2 = pick(testPerson, ['phone']) // Pick<Person, "phone">
const result3 = pick(testPerson, ['abc']) // expected error
解决方案
您可以重载pick
函数:
interface Person {
name: string;
age: number;
address: string;
phone: string;
}
const defaultProps = ['name', 'age'] as const;
type DefaultProps = typeof defaultProps;
function pick(obj: Person): Pick<Person, DefaultProps[number]>
function pick<Prop extends keyof Person, Props extends ReadonlyArray<Prop>>(obj: Person, props: Props): Pick<Person, Props[number]>
function pick<T extends keyof Person>(obj: Person, props = defaultProps) {
return props.reduce((res, prop) => ({
...res,
[prop]: obj[prop]
}), {} as Pick<Person, T>);
}
const testPerson = {
name: 'mitsos',
age: 33,
address: 'GRC',
phone: '000'
};
const result = pick(testPerson) // Pick<Person, "name" | "age">
const result2 = pick(testPerson, ['phone']) // Pick<Person, "phone">
const result3 = pick(testPerson, ['abc']) // expected error
pick
您可以在我的文章和其他答案
中找到更高级的类型: First , second , third
更新
props
此代码中的参数存在问题:
function pick<T extends keyof Person>(obj: Person, props: PropsOrDefault<T> = defaultProps): PickedPropOrDefault<PropsOrDefault<T>> {
return props.reduce((res, prop) => {
return {
...res,
[prop]: obj[prop]
}
}, {});
}
PropsOrDefault
可能等于这种类型:type UnsafeReduceUnion = DefaultProps | ReadonlyArray<'phone' | 'address'>
您可能已经注意到,联合中的这些数组是完全不同的。他们没有任何共同之处。
如果您要致电reduce
:
declare var unsafe:UnsafeReduceUnion;
unsafe.reduce()
你会得到一个错误,因为reduce
是not callable
推荐阅读
- postgresql - 为什么索引会增加 postgres 中的执行时间?
- magento - 如何在magento 2后端保存盘点之前进行验证
- python-3.x - 获取python窗口中的空闲CPU计数
- c# - 以 xamarin 形式连接 3 个表
- java - 在Java流中处理时如何将列表细分为多个列表?
- c++ - 解决多个重载
- ignite - Apache Ignite Yarn 部署 HDFS 问题
- go - 为什么在 golang 中写入全局地图时恢复不起作用
- wordpress - 如果 post 存在且 post_meta 存在
- angular - 在 agm 上放置自定义控制按钮