Ах, значит, вы не пытаетесь переименовать свойства; просто удалите любые конфликтующие свойства из одного из интерфейсов.
Это очень похоже на идею оператора типа распространения объекта , которого в настоящее время TypeScript не имеет как часть языка на уровне типа. В настоящее время система типов обрабатывает общие спреды как пересечение , что правильно только для не конфликтующих свойств.) На уровне значения / выражения TypeScript правильно обрабатывает спреды конкретных типов, так что вы можете получить конкретный Zoo
вы ищете, убедив систему типов, что у вас есть значение типа Pet
, значение типа Person
и значение, сформированное путем их распределения:
interface Person {
name: string
age: number
}
interface Pet {
age: string
trained: boolean // I added this because otherwise Zoo=Person which is weird
}
declare const person: Person; // pretend we have a person
declare const pet: Pet; // pretend we have a pet
const zoo = { ...pet, ...person }; // spread them into a new variable
type ZooType = typeof zoo; // get the type of that variable
// type ZooType = {
// name: string;
// age: number;
// trained: boolean;
// }
interface Zoo extends ZooType { }; // make it an interface because why not
Если вам не хочется разбираться со значениями (особенно если у вас нет каких-либо проблем), и вы хотите сделать это исключительно на уровне типов, вы можете самостоятельно создать оператор типа с распределением типа с помощью сопоставленные и условные типы. Один из разработчиков языка предложил реализацию из Spread<L,R>
, которая достаточно хорошо работает с некоторыми предостережениями относительно необязательных / readonly / etc свойств.
Для вашего случая, поскольку у вас нет необязательных или доступных только для чтения свойств, вот более простая реализация, которую я назову Merge<L, R>
:
type Merge<L, R> = R & Pick<L, Exclude<keyof L, keyof R>>;
И вы можете видеть, что он ведет себя подобно приведенному выше разбросу на уровне значений:
interface Zoo extends Merge<Pet, Person> { };
declare const zoo: Zoo;
zoo.name; // string
zoo.age; // number
zoo.trained; // boolean
Предостережения: если age
было необязательно в Person
, то Merge<Pet, Person>
сделает age
необязательным в Zoo
. Это может быть тем, что вы хотите, но спред не будет вести себя так; {...pet, ...person}
всегда будет иметь age
, поскольку Pet
требует его. Тогда в спреде Zoo["age"]
будет что-то вроде string | number
, с которым оператор Spread<L, R>
, связанный выше, будет работать более корректно. Также ни Merge<>
, ни связанный Spread<>
не гарантированно делают "правильные вещи" со свойствами readonly
, тем более что мне не ясно, что это за правильные вещи.
Хорошо, надеюсь, это поможет. Удачи!