Typescript &引用;剖析;具有泛型类型的对象(使用lodash/mapValues)

Typescript &引用;剖析;具有泛型类型的对象(使用lodash/mapValues),typescript,typescript-generics,Typescript,Typescript Generics,我希望实现一个通用函数,它接受一个类型化对象并返回该对象的一个变体(“被某个键解析”) 我的MWE遵循一个带有断点的示例,在该示例中,我有一个函数,可以从我的configresponsiveObj返回适当的屏幕大小属性。为简洁起见,该函数被锁定为sm,但我的键入问题应被捕获: const responsiveObj = { firstItem, secondItem }; // Where // (property) firstItem: Partial<Record<Breakpo

我希望实现一个通用函数,它接受一个类型化对象并返回该对象的一个变体(“被某个键解析”)

我的MWE遵循一个带有断点的示例,在该示例中,我有一个函数,可以从我的config
responsiveObj
返回适当的屏幕大小属性。为简洁起见,该函数被锁定为
sm
,但我的键入问题应被捕获:

const responsiveObj = { firstItem, secondItem };
// Where
// (property) firstItem: Partial<Record<Breakpoints, PrimaryProps>>
// (property) secondItem: Partial<Record<Breakpoints, PrimaryProps & SecondaryProps>>

...

const responsiveFn = <T extends any, K extends keyof T>(
  responsive: Record<K, ResponsiveProps<UnknownGeneric>>
) => {
  // Dummy sm output
  const out = _.mapValues(responsive, (o) => {
    return { ...o.sm };
  });

  return out;
};

const result = responsiveFn(responsiveObj);

// Height is part of PrimaryProps and is identified
result.firstItem.height;

// Visible is part of SecondaryProps and is _not_ identified
result.secondItem.visible;
const responsiveObj={firstItem,secondItem};
//在哪里
//(属性)第一项:部分
//(财产)第二项:部分
...
常数响应fn=(
回应:记录
) => {
//虚拟sm输出
常量输出=\映射值(响应,(o)=>{
返回{…o.sm};
});
返回;
};
常数结果=响应fn(响应obj);
//高度是PrimaryProps的一部分,已确定
结果:第一项:身高;
//Visible是次要道具的一部分,未被识别
result.secondItem.visible;
我希望
SecondaryProps
不要在函数中迷失方向


请参阅完整示例。

在类型级别,您所称的“分离”似乎如下所示:

  • 从am对象类型
    T
    开始,使用任意属性键,这些属性键的属性值是
    ResponsiveProps
    的某些子类型
  • 对于
    T
    中的每个属性键
    K
    ,输出对象类型在键
    K
    处也将有一个属性。所以我们想使用一个形式为
    {[K in keyof T]:…}
  • 对于每个属性值类型
    T[K]
    ,即
    ResponsiveProps
    的某个子类型,输出属性值类型将是
    断点处的属性值之一。也就是说,
    T[K][Breakpoints]
  • 请注意,这很可能是
    未定义的
    (因为
    ReponsiveProps
    具有所有可选属性),但即使输入不存在,您的输出似乎也会生成一个对象(您正在编写
    {…(o.sm)}
    ,如果
    o.sm
    未定义的
    ,那么它将是
    {}
    )。因此,我们希望指定use以从输出类型属性中删除
    未定义的可能性:
因此,我倾向于给
responsiveFn
一个这样的类型签名:

/* const responsiveFn: <T extends Record<keyof T, ResponsiveProps>(
    responsive: T) => { [K in keyof T]: NonNullable<T[K][Breakpoints]>; } */
请注意,编译器无法验证输出值是否符合带注释的映射类型,因此我使用
作为任何
来抑制编译器警告


如果我使用该版本,您将得到:

const result = responsiveFn(responsiveObj);
/* const result: {
    firstItem: PrimaryProps;
    secondItem: (PrimaryProps & SecondaryProps);
} */
console.log(result.firstItem.height) // 100
console.log(result.secondItem.visible) // false
看起来不错


这是您要找的吗?如果是这样的话,我很乐意写一个解释它的答案。如果没有,请详细说明问题;理想情况下,您不会依赖于任何第三方库(如lodash),除非该问题与这些库特别相关或与它们一起标记。。。因此,我将
.mapValues
替换为
对象.fromEntries()
对象.entries()
,以及数组
映射()
。让我知道。是的,@jcalz你的回答解决了我的问题。如果您能详细说明,我将不胜感激,我很难理解它是如何工作的。
const result = responsiveFn(responsiveObj);
/* const result: {
    firstItem: PrimaryProps;
    secondItem: (PrimaryProps & SecondaryProps);
} */
console.log(result.firstItem.height) // 100
console.log(result.secondItem.visible) // false