0

我试图找到一个简洁的函数,它只选择类型中感兴趣的属性(不仅在类型中,而且在运行时掩盖其他属性)。

目前我最好的解决方案是:


export function picker<T extends {}, K extends keyof T>(
    keys: K[],
): (m: T) => Pick<T, K> {
    return (m: T) => {
        const result: Partial<Pick<T, K>> = {};
        for (const key of keys) {
            result[key] = m[key];
        }
        return result as Pick<T, K>;
    };
}

interface Test {
    name: string;
    age: number;
    hobbies: string[];
}

const t: Test = {
    name: "yj",
    age: 12,
    hobbies: ["shopping"],
};

const pickTest = picker<Test, "name">(["name"]); //I want to remove the repetition in writing name twice here
// pickTest(t) should be of type `{name: string}` only

例子

4

1 回答 1

1

假设您希望对函数进行最小的更改(仅更改类型而不更改实现),我倾向于将T泛型从外部函数移动到它返回的函数。外部函数接受keystype的参数K[],因此可以K轻松推断,但无法推断T,因为没有T要查看的 type 值。在您当前的版本中,您必须手动指定T要避免的 。所以我们可以T进入返回的函数,因为该函数接受一个m类型的值T并且T可以从那里推断出来。

K extends keyof T当然,当T不在范围内时,我们不能再写了。相反,我们可以说K extends PropertyKey(它是一个类似键的类型) 然后T extends Record<K, any>. K我们没有限制在 key 上T,而是限制在Tkey 上拥有一个属性K

它看起来像这样:

function picker<K extends PropertyKey>(
  keys: K[],
): <T extends Record<K, any>>(m: T) => Pick<T, K> {
  return <T extends Record<K, any>>(m: T) => {
    const result: Partial<Pick<T, K>> = {};
    for (const key of keys) {
      result[key] = m[key];
    }
    return result as Pick<T, K>;
  };
}

现在我们可以调用picker并且pickTest无需手动指定任何类型参数;编译器可以很好地推断它们:

const pickTest = picker(["name"]);
const justName = pickTest(t); // Pick<Test, "name">
console.log(justName); // {name : "yj"}
justName.name.toUpperCase();

Playground 代码链接

于 2020-12-24T03:56:50.603 回答