Javascript “的TypeScript通用类型”;挑选;函数(结果对象值类型)

Javascript “的TypeScript通用类型”;挑选;函数(结果对象值类型),javascript,typescript,types,generic-type-argument,Javascript,Typescript,Types,Generic Type Argument,为拾取函数写入类型时出现问题。当只拾取一个或多个具有相同类型值的关键点时,一切正常。但是,如果我尝试选择几个键,并且它们的值是不同的类型,我将得到一个错误。不太清楚我在哪里犯了错误 谢谢你抽出时间 export interface Mapper<T = any, R = any> { (arg: T): R; } export function pick<O, T extends keyof O>(keys: T[], obj?: O): { [K in T]:

为拾取函数写入类型时出现问题。当只拾取一个或多个具有相同类型值的关键点时,一切正常。但是,如果我尝试选择几个键,并且它们的值是不同的类型,我将得到一个错误。不太清楚我在哪里犯了错误

谢谢你抽出时间

export interface Mapper<T = any, R = any> {
  (arg: T): R;
}


export function pick<O, T extends keyof O>(keys: T[], obj?: O): { [K in T]: O[T] };

export function pick<T>(keys: T[], obj?: never): Mapper;

export function pick<O, T extends keyof O>(keys: T[], obj?: O) {
  const picker: Mapper<O, { [K in T]: O[T] }> = _obj =>
    keys.reduce((acc, key) => {
      if (key in _obj) {
        acc[key] = _obj[key];
      }
      return acc;
    }, {} as O);

  return obj ? picker(obj) : picker;
}

const obj = { someKey: 'value', otherKey: 42, moreKey: ['array value'] };

const newObj = pick(['otherKey'], obj);
//OK. TS type for newObj is {otherKey: number}

const n: number = newObj.otherKey;
// OK

const otherNewObj = pick(['otherKey', 'someKey'], obj);
//no really OK. TS type for otherNewObj is {otherKey: number | string, someKey: number | string}

const m: number = otherNewObj.someKey;
// Error. Type string | number is not assignable to the number
导出接口映射器{
(arg:T):R;
}
导出函数选取(键:T[],obj?:O):{[K in T]:O[T]};
导出函数拾取(键:T[],对象?:从不):映射器;
导出功能拾取(键:T[],对象?:O){
常量选择器:映射器=\u obj=>
按键。减少((acc,按键)=>{
如果(输入_obj){
acc[键]=_obj[键];
}
返回acc;
},{}as O);
返回obj?选择器(obj):选择器;
}
const obj={someKey:'value',otherKey:42,moreKey:['array value']};
const newObj=pick(['otherKey'],obj);
//嗯。newObj的TS类型为{otherKey:number}
常数n:number=newObj.otherKey;
//嗯
const otherNewObj=pick(['otherKey','someKey',],obj);
//不,真的很好。otherNewObj的TS类型为{otherKey:number | string,someKey:number | string}
常数m:number=otherNewObj.someKey;
//错误。类型字符串|编号不能分配给该编号

您的映射类型中有一个错误,您可能希望使用
O[K]
而不是
O[T]
,因此您最终得到了
{[K in T]:O[K]}
。您需要的是每个键
K
的类型,而不是
T
联合中所有属性的类型

我还将使用
Pick
,因为
Pick
是同态的,并且将保留诸如
readonly
optional
之类的修饰符

另外
obj?:never
可能不做您希望它做的事情,任何事情都可以分配给
never
,您最好省略重载中的参数:

export function pick<O, T extends keyof O>(keys: T[], obj?: O): Pick<O, T>;
export function pick<T>(keys: T[]): Mapper;
export function pick<O, T extends keyof O>(keys: T[], obj?: O) {
    //....
}
导出功能拾取(键:T[],obj?:O):拾取;
导出函数拾取(键:T[]):映射器;
导出功能拾取(键:T[],对象?:O){
//....
}

非常感谢,完美的答案!我只是没想过在这个场景中使用pick。另外,我可以问一下关于重载的问题吗?一般来说,有没有一种方法可以在没有重载但使用条件类型的情况下编写相同的类型?