Как исключить ключ из интерфейса в TypeScript

В TypeScript вы можете объединить два типа интерфейса, например

interface Foo {
    var1: string
}

interface Bar {
    var2: string
}

type Combined = Foo & Bar

Вместо сочетания клавиш я хочу исключить ключи из одного интерфейса в другой. В любом случае вы можете сделать это в TypeScript?

Причина в том, что у меня есть HOC, который управляет значением свойства для другого завернутого компонента, такого как

export default function valueHOC<P> (
  Comp: React.ComponentClass<P> | React.StatelessComponent<P>
): React.ComponentClass<P> {
  return class WrappedComponent extends React.Component<P, State> {
    render () {
      return (
        <Comp
          {...this.props}
          value={this.state.value}
        />
      )
    }
}

С этим я могу написать

const ValuedComponent = valueHOC(MyComponent)

затем

<ValuedComponent />

но проблема в том, что возвращаемый тип компонента также использует тип реквизита из данного компонента, поэтому TypeScript будет жаловаться и попросить меня предоставить поддержку value. В результате мне придется написать что-то вроде

<ValuedComponent value="foo" />

Какое значение в любом случае не будет использоваться. Я хочу здесь вернуть интерфейс без определенных ключей, я хочу иметь что-то вроде этого

React.ComponentClass<P - {value: string}>

Тогда value не потребуется в возвращаемом компоненте. Возможно ли это в TypeScript?

Ответ 1

В TypeScript 2.8 теперь вы можете делать следующее:

interface Foo {
    attribute1: string;
    optional2?: string;
    excludePlease: string;
}

// Define Omit.  Can be defined in a utilities package
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

// Use Omit to exclude one or more fields (use "excludePlease"|"field2"|"field3" etc to exclude multiple)
type Bar = Omit<Foo, "excludePlease">
const b: Bar = {
    attribute1: ''
};

Так что в связи с вашим вопросом может быть то, что вы хотите:

export default function valueHOC<P> (
  Comp: React.ComponentClass<P> | React.StatelessComponent<P>
): React.ComponentClass<Omit<P, "value">> {
  return class WrappedComponent extends React.Component<Omit<P, "value">, State> {
    render () {
      return (
        <Comp
          {...this.props}
          value={this.state.value}
        />
      )
    }
}

Ответ 2

Существует библиотека типов утилит с отображенным типом Subtract:

import { Subtract } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };

type RequiredProps = Subtract<Props, DefaultProps>;
// Expect: { name: string; visible: boolean; }

Ответ 3

Вы не можете удалить свойства из уже существующих интерфейсов. Даже попытка расширить существующий интерфейс с интерфейсом, имеющим свойство value, заданное как необязательное, вернет ошибку.

Чтобы избежать этой проблемы, измените типичность целевого компонента, поэтому свойство value не является обязательным.

например.

// ...
class MyComponent extends React.Component<{value?: string}, State> {
// ...
}

а затем компонент, созданный при использовании функции высокого порядка

const valuedComponent = valueHOC(MyComponent);

не будет запрашивать value prop.