如何捕获嵌套 属性 的类型参数并将其映射到其他对象

How to capture type argument of nested property and map it to something else

我真的不知道怎么问这个问题,所以我认为最好的方法是举例说明我正在尝试做的事情。假设我有以下对象:

const obj = {
  one: 'some string',
  two: new Set<string>(),
};

现在我想编写一个函数,接收该对象并将 Set 转换为相同类型的 Array

这是未类型化的 javascript 实现:

const obj = {
  one: 'some string',
  two: new Set().add('one').add('two'),
};

function convertToArrays(objWithSets) {
  return Object.entries(objWithSets).reduce((objectWithArrays, [key, value]) => {
    if (value instanceof Set) {
      objectWithArrays[key] = Array.from(value);
    } else {
      objectWithArrays[key] = value;
    }
    return objectWithArrays;
  }, {});
}


console.log('converted', convertToArrays(obj));

如何正确输入上述函数? 澄清一下:它可以接受任何对象(不仅仅是一个,两个示例)并且如果它看到 Set<T>,它将其转换为 Array<T>.

我知道它需要捕获内部 Set 的类型(在本例中为 string)并将该类型有条件地映射到 Array<string>.

谢谢!

您可以混合使用映射类型和条件类型来执行此操作:

type InnerSetToArray<T> = { 
    [P in keyof T]: 
        T[P] extends Set<infer U> 
            ? Array<U> 
            : T[P] 
};

type InnerSet = { one: number, two: Set<string>, three: Set<Function>, four: Date };

// InnerArray === { one: number, two: string[], three: Function[], four: Date }
type InnerArray = InnerSetToArray<InnerSet>;

编辑:原创,下面过于具体的答案:

我们开始吧,基本上就像您描述的那样:

function convertToArrays<T extends { one: string, two: Set<any> }>(objWithSets: T):
    T extends { one: string, two: Set<infer U> }
        ? { one: string, two: Array<U> }
        : never {
  /* ... */
}

// typeof x === { one: string, two: number[] }
const x = convertToArrays({ one: "hello", two: new Set([1, 2, 3]) })

我们允许它最初是 Set<any> 只是作为类型保护,然后根据条件推断实际类型。条件在匹配失败时缩小到 never,这应该没问题,因为初始检查理论上保证条件将始终计算为真。