Typescript: изменение имени конфликтующего свойства при расширении интерфейса - PullRequest
0 голосов
/ 09 мая 2019

Есть ли способ сделать что-то подобное с машинописью, переименовав имя свойства или что-то еще?

interface Person {
    name: string
    age: number
}

interface Pet {
    age: string
}

interface Zoo extends Pet, Person {}

Без получения этой ошибки:

Интерфейс «Zoo» не может одновременно расширять типы «Person» и «Pet» Именованные свойства 'age' типов 'Person' и 'Pet' не идентичны. Ts (2320)

[EDIT] * * +1010

Я ищу способ получить этот результат:

interface Zoo {
    name: string
    age: number
}

1 Ответ

1 голос
/ 10 мая 2019

Ах, значит, вы не пытаетесь переименовать свойства; просто удалите любые конфликтующие свойства из одного из интерфейсов.

Это очень похоже на идею оператора типа распространения объекта , которого в настоящее время 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, тем более что мне не ясно, что это за правильные вещи.

Хорошо, надеюсь, это поможет. Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...