Я пытаюсь создать функцию, которая будет возвращать общий тип объекта с ключами, полученными из аргумента, переданного в эту функцию. Упрощенный пример:
// What do I put here for this to work?
type ObjectB<T> = {};
declare function makeObjectB<T>(a: T): ObjectB<T>;
const objectB = makeObjectB({
name: "foo"
});
console.info(objectB.foo)
typeof objectB
приведет к чему-то вроде:
{
foo: string
}
Бонусные баллы, если следующий пример также может поддерживаться:
// What do I put here for this to work?
type ObjectB<T> = {};
declare function makeObjectB<T>(a: T[]): ObjectB<T[]>;
const objectB = makeObjectB([{ name: "foo" }, { name: "bar" }]);
console.info(objectB.foo)
console.info(objectB.bar)
typeof objectB => { foo: string; bar: string }
Не совсем, фактические типы и функции, для которых я на самом деле использую это, - это нечто совершенно другое.
Конечно, с сопоставленным типом:
type ObjectB<T extends { name: string }> = {
[K in T["name"]]: string;
};
Вы заметите extends { name: string }
после T
. Это общее ограничение, которое равно похожий для аргумента типа параметра функции.
Внутри сопоставленного типа мы просматриваем каждый K
в T["name"]
и сопоставляем его с string
.
Итак, если бы у нас было это: ObjectB<{ name: "foo" }>
, T["name"]
было бы "foo"
, и этот тип привел бы к:
{
foo: string;
}
Теперь с этим типом мы можем написать нашу сигнатуру функции:
declare function makeObjectB<T extends { name: string }>(a: T): ObjectB<T>;
Вы также заметите, что здесь присутствует такое же общее ограничение. Это сделано для того, чтобы TypeScript мог использовать T
из makeObjectB
с ObjectB
.
А для бонусных баллов мы можем определить перегрузку:
declare function makeObjectB<T extends ReadonlyArray<{ name: string }>>(a: T): ObjectB<T[number]>;
T
теперь может быть любым массивом объектов, у которых есть ключ name
, указывающий на строку.
Другое отличие здесь заключается в использовании ObjectB<T[number]>
вместо просто ObjectB<T>
. Это позволяет нам получить все элементы в массиве (технически здесь кортеж) как объединение, что означает, что T["name"]
теперь что-то вроде "foo" | "bar"
.
Вы можете попробовать это решение здесь.
Вы в основном пытаетесь определить тип на основе какой-то схемы, подобной JSON-Schema?