Как заставить перечислять оператор спреда только через нефункциональные свойства? - PullRequest
0 голосов
/ 04 июля 2018

Стек: ReactJS 16.x, Typescript 2.8.1, проект создания-реагирования-приложения.

Я получаю ошибку типа при использовании оператора распространения для передачи props из класса TypeScript в компонент React.

Ошибка возникает только тогда, когда в классе определена функция. Если у класса есть переменная выражения функции, оператор распространения работает нормально. Я считаю, что это связано с перечислением свойств в классе. Итак, я использую декоратор, чтобы пометить функцию как не перечисляемую, но все еще получаю ту же ошибку. Ниже приведен код:

Message - это класс, который я пытаюсь распространить в React Component.

export class Message {
  constructor() {
    this.init2 = (msg: string) => {
      this.msg = 'init2';
      return this;
    }
  }

  public msg: string;

  // This works with spread operator
  public init2: (msg: string) => Message;

  // This will cause the spread operator to fail
  public init(msg: string): Message {
    this.msg = msg;
    return this;
  }

  // Even with decorator to turn off enumeration, spread operator fails
  @enumerable(false)
  public initNoEnum(msg: string): Message {
      this.msg = msg;
      return this;
  }
}

Компонент ReactJS, чья опора определяется как Message:

export class MessageComponent extends React.Component<Message, any>{
  render() {
    return (<div>{this.props.msg}</div>);
  }
}

Метод визуализации, который использует MessageComponent:

  public render() {
    const msg = new Message().init('hello world!');
    return <MessageComponent {...msg} /> // The spread here fails
  }

Функция декоратора enumerable:

  export function enumerable(value: boolean): any {
      return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
      descriptor.enumerable = value;
    };
  }

TSconfig:

"compilerOptions": {
  "outDir": "./build",
  "module": "esnext",
  "target": "es5",
  "lib": [ "es6", "dom" ],
  "sourceMap": true,
  "allowJs": true,
  "jsx": "react",
  "moduleResolution": "node",
  "rootDir": "src",
  "forceConsistentCasingInFileNames": true,
  "noImplicitReturns": true,
  "noImplicitThis": true,
  "noImplicitAny": true,
  "strictNullChecks": true,
  "suppressImplicitAnyIndexErrors": true,
  "noUnusedLocals": true,
  "experimentalDecorators": true
},

Если я закомментирую init и initNoEnum и оставлю init2, оператор распространения работает. При init и initNoEnum оператор распространения не работает с аналогичным сообщением:

Тип '{msg: строка; init2: (msg: string) => Сообщение; } 'нельзя назначить типу IntrinsicAttributes & IntrinsicClassAttributes & Readonly <{children ?: ReactNod ...'. Тип '{msg: строка; init2: (msg: string) => Сообщение; } 'нельзя назначить типу «Только чтение». Свойство 'init' отсутствует в типе '{msg: string; init2: (msg: string) => Сообщение; }».

Что я делаю не так? Как сделать так, чтобы оператор распространения только перечислял через свойства, а не функции?

1 Ответ

0 голосов
/ 04 июля 2018

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

Вы не можете использовать оператор распространения, чтобы получить только нефункциональные свойства по умолчанию, потому что функции - это свойства, но, возможно, с вашим волшебством tsconfig это должно работать, однако вы можете изменить объект, передаваемый оператору распространения сначала вместо.

Чтобы использовать синтаксис распространения для получения только нефункциональных свойств без магии tsconfig, я бы предложил использовать функцию для фильтрации свойств функции, а затем использовать оператор распространения следующим образом:

const filterOutFunctions = object => {
  return Object.keys(object)
    .filter(key => typeof(object[key]) !== 'function')
    .reduce((filteredObj, currentItem) => {
      filteredObj[currentItem] = object[currentItem]
      return filteredObj
    }, {})
}

const objectWithFunctions = {
  aFunction() {},
  aProperty: 'A good ol string'
}

// Now you can do spread operator stuff with a filtered version like so:
{...filterOutFunctions(objectWithFunctions)}
// returns: { aProperty: 'A good ol string' }

Это работает путем итерации по keys из object с .filter, чтобы отфильтровать ключи, указывающие на функцию. Затем мы собираем все оставшиеся свойства, присваивая их новому пустому объекту с помощью .reduce.

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