Material-ui: Ошибка типа Typescript в компоненте, возвращаемом withStyles ()

Созданный на 28 сент. 2017  ·  55Комментарии  ·  Источник: mui-org/material-ui

При использовании withStyles() hoc в машинописном тексте я получаю следующую ошибку при попытке использовать возвращенный компонент:

Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{ children?: ReactNode; }> & Reado...'.
  Type '{}' is not assignable to type 'Readonly<WithStyles<"main">>'.
    Property 'classes' is missing in type '{}'.
  • [x] Я искал проблемы в этом репозитории и считаю, что это не дубликат.

Похоже, что это изменение определения типа может быть связано с этой проблемой.

Ожидаемое поведение

Учитывая приведенный ниже код компонента App , я смогу использовать компонент <App /> без ошибки типа, как это было в 1.0.0-beta.10.

Текущее поведение

Учитывая приведенный ниже код компонента App , попытка использовать <App /> приводит к вышеупомянутой ошибке.

Код

import * as React from 'react';
import { withStyles } from 'material-ui/styles';

const styles = {
    main: {
        marginTop: 48,
        padding: 10,
    },
    foo: {
        margin: 0,
    },
};

interface Props {
    message: string;
};

type ClassNames = { classes: { [className in keyof typeof styles]: string } };

class App extends React.Component<Props & ClassNames> {
    render() {
        const { classes, message } = this.props;
        return (
            <div className={classes.main}>
                <div className={classes.foo} >
                    Hello World! {message}
                </div>
            </div>
        );
    }
}

export default withStyles(styles)(App);

Контекст

Код работал нормально в 1.0.0-beta.10, когда я обновился до 1.0.0-beta.12, я получил ошибку типа.

В предоставленном фрагменте кода я использовал уловку keyof typeof styles чтобы мне не нужно было дважды определять список имен классов (мне категорически не нравится повторяемость). Я также пробовал другие варианты:

type ClassNames = WithStyles<keyof typeof styles>;

и делаем это более распространенным способом (как показано в styles.spec.tsx ):

type ComponentClassNames = 'main' | 'foo';
type ClassNames = WithStyles<ComponentClassNames>;

Я все еще получаю ту же ошибку.

Кажется, что предыдущее определение типа вернет компонент, тип реквизита которого будет StyledComponentProps который имеет необязательное свойство classes . Новое определение ...

<P, C extends React.ComponentClass<P & StyledComponentProps<Names>>>(
    component: C
  ): C;

... возвращает тот же тип C что и компонент, это означает, что передача ClassNames которая не помечена как необязательная, распространяется на возвращаемый компонент. Я вижу здесь упомянутое использование Partial<> которое я считаю неприглядным.

Ваше окружение

| Технология | Версия |
| -------------- | --------- |
| Материал-UI | 1.0.0-beta.12 |
| Реагировать | 15.6.1 |
| браузер | Хром 61.0.3163.100 |

discussion typescript

Самый полезный комментарий

Я решил использовать перекомпоновку

пример

import { StyleRules, Theme, withStyles } from "material-ui/styles";
import * as React from "react";
import { compose } from "recompose";

interface IProps {
    classes?: any; // <-- add question mark
    text: string;
}

const styles = (theme: Theme): StyleRules => ({
    root: {

    },
});

@compose(
    withStyles(styles),
)
export class MyComponent extends React.Component<IProps> {
    render() {
        const { classes, text } = this.props;
        return (
            <div className={classes.root}>
                {text}
            </div>
        );
    }
}

Все 55 Комментарий

@cfilipov при декорировании класса компонента вы должны использовать StyledComponentProps вместо WithStyles , а если в режиме строгой проверки типа вам нужно использовать ненулевой оператор утверждения ! для извлечения поля classes . Это компромисс, позволяющий использовать withStyles в качестве декоратора класса. Декораторы классов в TypeScript страдают от ограничения , заключающегося в

  1. не поддерживают использование withStyles в качестве декоратора класса
  2. требовать, чтобы вы передавали фиктивную опору classes при создании элемента декорированного типа компонента (предыдущий компромисс, который, возможно, был более раздражающим )
  3. требовать, чтобы classes считалось допускающим значение NULL внутри компонента, вынуждая вас использовать оператор ! при доступе к его полям ( текущий компромисс )

Я настоятельно рекомендую, чтобы, если ваш компонент не имеет состояния, вы использовали функциональный компонент без состояния, который потребует меньше аннотаций типов и будет более безопасным по типу:

export default withStyles(styles)<Props>(({ classes, message }) => (
  <div className={classes.main}>
    <div className={classes.foo}>
      Hello World! {message}
    </div>
  </div>
));

Я вижу здесь упомянутое использование Partial <>, которое я считаю неприглядным.

Если вы прочитаете мое продолжение к этому комментарию, вы увидите, что Partial<> не требуется.

Если вы прочитаете мое продолжение к этому комментарию, вы увидите, что Partial <> не требуется.

Я видел ваш комментарий по поводу Partial<> . Использование StyledComponentProps сути означает одно и то же (в этом определении используется Partial<> ). Моя претензия к этому заключается в том, что теперь к именам классов необходимо обращаться с помощью ! (как вы упомянули). Я думаю, что передача фиктивного classes prop или требование использования ! - плохой компромисс.

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

@cfilipov моим первым рефакторингом типизации withStyles было выбрать вариант (1), т.е. сделать типизацию полностью правильной для компонентов класса и функции, за счет использования withStyles в качестве декоратора класса. . Затем я получил обратную связь , что с помощью синтаксиса декоратора был популярным запросом, поэтому я перешел на вариант (3). Я счастлив пересмотреть это решение; Я тоже предпочел бы безопасность типов поддержке декораторов в их текущем полуфункциональном состоянии.

Да, я понимаю желание поддержать такую ​​популярную просьбу. Я тоже хочу использовать декораторы, но каждый раз сталкиваюсь с множеством проблем с ними (кроме mui), поэтому я лично решил не использовать их, пока они не будут готовы.

Похоже, вы разделяете мою озабоченность, и мне нечего добавить, поэтому, надеюсь, другие люди могут предоставить обратную связь в этом направлении, чтобы помочь повлиять на нее.

Я перешел на beta.13 с beta.10, чтобы посмотреть, не изменилось ли что-нибудь, и да, это реальная проблема. Чтобы бросить сюда мои 2 цента, декораторы для меня экспериментальные. Очевидно, что в будущем они могут быть изменены. А до тех пор я полностью поддержу 100% точный способ. Я бы предпочел иметь согласованную безопасность типов, чем взламывать свои типы, чтобы все работало.

8550 выглядит как еще одно свидетельство того, что людей это сбивает с толку, и мы должны рассмотреть отказ от поддержки @withStyles() в качестве декоратора (в TypeScript).

Вот как бы выглядело "украшение" класса, если бы мы сделали правильную типизацию:

type NonStyleProps = {
  text: string
};

const styles = {
  root: {
    backgroundColor: 'red'
  }
};

const DecoratedComponent = withStyles(styles)(
  class extends React.Component<NonStyleProps & WithStyles<'root'>> {
    render() {
      return (
        <div className={this.props.classes.root}>
          {this.props.text}
        </div>
      );
    }
  }
);

@pelotom Из-за этой проблемы мне еще предстоит перейти от beta.10. Раньше я прокомментировал стиль класса с помощью метода подключения Redux. Я думаю, что это относительно просто и надежно. в # 8059 третий комментарий относится к типам.

@pelotom Большое спасибо за то, что withStyles отказался от поддержки декораторов, чтобы повысить безопасность типов.

мы должны рассмотреть отказ от поддержки @withStyles () в качестве декоратора (в TypeScript).

@pelotom Я лично за это изменение. @sebald Что ты хочешь здесь делать?

Это простое изменение; Я пошел дальше и открыл PR на случай, если вы захотите пойти с этим 🙂

@pelotom, будет ли набор текста работать, если я использую его вот так?

interface IStyles {
    // styles interface
}
interface IHeaderInfoStyles {
    classes: any;
}
interface IHeaderInfoProps {
    // properties resulting from dispatches
}
interface IHeaderInfoInjectedProps {
   // props injected from parent if any
}
interface IHeaderInfoDispatchProps {
    // dispatches
}
interface IHeaderInfoState {
    // your state for the class
}

type HeaderInfoProps = IHeaderInfoProps & IHeaderInfoInjectedProps & IHeaderInfoDispatchProps & IHeaderInfoStyles;

class HeaderInfo extends Component<HeaderInfoProps, IHeaderInfoState> {

export const HeaderInfo_container = withStyles<IHeaderInfoInjectedProps, IStyles>(styles)(
    connect<IHeaderInfoProps, IHeaderInfoDispatchProps, (IHeaderInfoInjectedProps & IHeaderInfoStyles)>(mapStateToProps, mapDispatchToProps)(HeaderInfo),
);

@marcusjwhelan withStyles больше не принимает 2 параметра типа, и вам не нужно предоставлять параметр типа для стилей (его можно вывести из styles ). Вместо этого вы можете написать

withStyles(styles)<NonStyleProps>(...);

Если вы укажете типы для mapStateToProps и mapDispatchToProps я могу показать вам, как это будет выглядеть для вашего примера.

tl; dr; Давайте внесем изменения и посмотрим, каков люфт, я думаю 👷🏻


@oliviertassinari @pelotom ¯_ (ツ) _ / ¯ Я не использую декораторы, поэтому лично меня это изменение не волнует, потому что меня это не касается. Но похоже, что многих действительно волнует эта «особенность». Именно поэтому мы добавили его в первую очередь. Это ИМХО то, что здесь в приоритете.

Я очень доволен изменениями withStyles , но когда вы смотрите на другие более функциональные библиотеки, такие как ramda или recompose , типизация не такая строгая, они также не являются супербезопасными. Часто вам нужно передать общий тип, который представляет возвращаемое значение функции. Неприятно, но это будет работать для 99,9% пользователей.

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

Кроме того, я немного сбит с толку, какие проблемы у людей возникают с декораторами (относительно «неработающих»). Библиотеки, такие как Angular и https://nestjs.com/, в конце концов, активно их используют. В нашем случае люди могут просто добавить WithStyles к реквизиту, и все будет в порядке.

@sebald

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

Я не уверен, что вы имеете в виду. Никогда не было набора текста, который позволял бы людям безболезненно использовать декораторы. Первая реализация страдала от # 8267, заключающегося в том, что вы не могли создать элемент декорированного компонента без передачи фиктивного classes prop, например <StyledComp classes={{} as any} /> . Вторая (текущая) реализация страдает обратной проблемой: classes потенциально рассматривается как undefined в классе компонентов. Если вы хотите использовать декораторы TypeScript в их текущей форме, это ваши единственные 2 варианта; выбрать свой яд.

Третий способ - использовать правильный тип, так что classes определяется внутри класса, но не обязательно для передачи в качестве опоры. Чтобы иметь оба этих условия, вам нужно отказаться от декораторов.

@pelotom Да, извините. Ты прав. На самом деле не мой день ... Итак, давайте объединимся!

@sebald

Кроме того, я немного сбит с толку, какие проблемы у людей возникают с декораторами (относительно «неработающих»). Библиотеки, такие как Angular и https://nestjs.com/, в конце концов, активно их используют.

Я не уверен, как они используются в Angular, но, безусловно, есть случаи, когда декораторы можно использовать безболезненно; в основном, если декоратору не нужно менять тип класса, который он украшает, они работают нормально. Это не та ситуация, которая у нас здесь; withStyles необходимо изменить тип компонента, который он украшает.

@pelotom Да, именно так. Плохая просто мутация. Фактически, способ, которым TS в настоящее время реализует декораторы, может быть даже хорош для пользователей Angular, поскольку декораторы AFAIK устанавливают контракты с фреймворком, например «зарегистрировать этот класс как компонент» или «добавить метаданные, чтобы я мог использовать это в DI. «... Бог, даже когда я пишу об этом, заставляет меня чувствовать

@pelotom причина, по которой у меня есть типы, - это обеспечение безопасности типов для моих компонентов. В настоящее время типы не имеют типобезопасности, когда дело касается компонентов. InjectedProps в моем примере - это типы, которые требуются компоненту для работы. Типы для подключения от react-redux необходимости в том , что из реквизита , которые приходят из mapStateToProps и DispatchProps , которые приходят из mapDispatchToProps.

В самом конце должны быть injectedProps, чтобы мой родительский компонент знал, что мне нужно их ввести, иначе мой проект не будет компилироваться. (это то, что я хочу). Переносится ли это изменение обратно на этот тип безопасности?

@marcusjwhelan еще раз, если вы можете предоставить полный (но минимальный) пример, который компилировался в бета-версии 10, я могу показать вам, как выполнить миграцию. AFAIK новая версия должна быть такой же выразительной и более безопасной, чем раньше.

@pelotom Глупый вопрос, есть ли способ получить уведомление о выходе новой версии?

@wcandillon Следуйте за нами в Twitter.

@pelotom Я опубликовал пример выше ... Зачем вам нужно видеть что-то большее, чем это? Вы можете предположить, что это свойства a, b, c, d, e. Единственное, что внедренный реквизит должен быть выдан в качестве требования.

Редактировать

Я понял.

Я вмешиваюсь в это обсуждение немного поздно, но я наблюдал похожую ошибку, о которой упоминалось здесь, и мне еще предстоит определить, как я могу ее исправить. Я использую [email protected] и [email protected] .

const LoginForm = withStyles(styles)(
    class extends React.Component<WithStyles<'root' | 'button'>, ILoginFormState> {
    // ...
    }
);

render(
  <MuiThemeProvider theme={theme}>
    <LoginForm />
  </MuiThemeProvider>,
  document.getElementById('login-form')
);

В этом конкретном случае я получаю следующее сообщение об ошибке:

Type '{}' is not assignable to type 'IntrinsicAttributes & WithStyles<"root" | "button"> & StyledComponentP...'.
  Type '{}' is not assignable to type 'WithStyles<"root" | "button" | "progress" | "textField">'.
    Property 'classes' is missing in type '{}'.
 not assignable to type 'WithStyles<"root" | "button" | "progress" | "textField">'.
    Property 'classes' is missing in type '{}'.

при декорировании класса компонента следует использовать StyledComponentProps вместо WithStyles.

@pelotom - есть ли где-нибудь такой пример? У меня масса проблем с определением стиля класса компонента с отслеживанием состояния в TypeScript.

@iamjem это немного сложно сказать, поскольку вы не предоставили styles , но похоже, что первая проблема заключается в том, что у вас больше ключей класса, упомянутых в styles чем вы указываете в WithStyles<...> . Я думаю, если вы измените его на

const LoginForm = withStyles(styles)(
    class extends React.Component<WithStyles<keyof typeof styles>, ILoginFormState> {
    // ...
    }
);

он должен позаботиться о первой проблеме. Тогда похоже, что есть вторая проблема, которая заключается в том, что результирующий тип LoginForm равен

React.ComponentType<WithStyles<"root" | "button"> & StyledComponentProps<"root" | "button">>

что явно неверно; похоже, что отсутствие нестилевых реквизитов сбивает с толку систему типов. Вы можете помочь, четко указав, что такое не-style props, передав {} в качестве аргумента типа:

const LoginForm = withStyles(styles)<{}>( // <-- note the type argument
    class extends React.Component<WithStyles<keyof typeof styles>, ILoginFormState> {
    // ...
    }
);

Извините, это так сложно, я хотел бы знать более простой способ заставить этот материал работать!

Это сработало! Спасибо за быструю помощь @pelotom. Я давно использую React, но совсем недавно перешел на Material-ui и подумал, что попробую Typescript, пока я на нем. Излишне говорить, что я нахожу некоторые крайние случаи, когда трудно сказать, как сделать Typescript счастливым.

Я решил использовать перекомпоновку

пример

import { StyleRules, Theme, withStyles } from "material-ui/styles";
import * as React from "react";
import { compose } from "recompose";

interface IProps {
    classes?: any; // <-- add question mark
    text: string;
}

const styles = (theme: Theme): StyleRules => ({
    root: {

    },
});

@compose(
    withStyles(styles),
)
export class MyComponent extends React.Component<IProps> {
    render() {
        const { classes, text } = this.props;
        return (
            <div className={classes.root}>
                {text}
            </div>
        );
    }
}

Я боролся с этой проблемой (и # 8704), но за последние несколько дней не дал однозначного результата. Тогда я последовал совету @pelotom :

вы должны использовать StyledComponentProps вместо WithStyles

и искал на GitHub похожие способы решения этой проблемы. И нашел ОДИН рабочий пример 😂. Тем не менее, это хороший вариант, и он решил мою проблему - отдельный контейнер и компонент с TypeScript, являющимся счастливым файлом cookie: упомянутый здесь пример ( Примечание: в моем случае сопоставление компонентов находится в отдельном файле контейнера, но идея заключается в тем же.).

Если кто-то думает, что это плохое решение, я открыт для любых изменений и идей. ПРАВИЛЬНО, я просто рад, что мой код перестал жаловаться.

type Styles = 'foo';
const styles: StyleRulesCallback<Styles> = (theme: Theme) => ({
    foo: {
        position: 'relative',
    }
});

interface Props {
  something: string;
}

class Sidebar extends React.Component<Props & WithStyles<Styles>> {
    render() {
        const { classes, something } = this.props;

        return (
                    <div className={classes.foo}>{something}</div>
        );
    }
}

export default withStyles(styles)<Props>(Sidebar);

Я не хочу создавать новую проблему, но я пробовал все, что видел в документации, пример и передавал проблемы, даже с перекомпоновкой, но я не могу заставить свой компонент работать, когда я добавляю к нему некоторые свойства.
И ресурсы, которые я нашел, в основном относятся к более старым версиям TS, MUI или даже React.

Вот мой компонент:

import React from 'react';
import AppBar from 'material-ui/AppBar';
import { withStyles, WithStyles, StyleRulesCallback } from 'material-ui/styles';

const styles: StyleRulesCallback<'positionFixed'> = () => ({
  positionFixed: {
    top: 'auto',
    bottom: 0,
  },
});

const decorate = withStyles(styles);

interface Props {
   someProp: string;
};

export const BottomNav = decorate<Props>(
  class extends React.Component<Props & WithStyles<'positionFixed'>, {}> {
    render() {
      return (
        <AppBar />
      );
    }
  }
);

export default BottomNav;

И ошибка:

TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & Props & StyledComponentProps<"positionFixed"> & { children?: ReactNode; }'.
  Type '{}' is not assignable to type 'Props'.
    Property 'someProp' is missing in type '{}'.

Я новичок в TS, но нахожу страницу документации и пример довольно запутанными и / или неполными.

Если у вас есть идеи, спасибо ;-)

@otroboe , вы

<BottomNav />

Если это так, проблема в том, что вам нужно предоставить опору someProp (которая требуется в соответствии с вашим определением Props ):

<BottomNav someProp="foo" />

Позор мне ... Ой, позор мне.
Я был так сосредоточен на интеграции TS, что забыл оглянуться и сделать несколько шагов назад.

Большое спасибо @pelotom : smile:

@otroboe Также удалите дублирование строки ...

type Styles = 'positionFixed';

Хотелось бы, чтобы это было проще ...

Да, я тоже это сделал, спасибо: +1:

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

Есть какие-нибудь подсказки, почему это происходит?

@ nishmeht7 вы можете опубликовать автономный сниппет?

@pelotom Я только что работал над его созданием, и он отлично работает в моей песочнице. В настоящее время я работаю над большим приложением и все еще использую версию mui 1.2.2, в то время как моя версия env для песочницы является последней. Поэтому я предполагаю, что после обновления версии я не смогу воспроизвести свою ошибку.

Я последовал примеру базовой формы из https://material-ui.com/demos/selects/, но получил жалобы на то, что в theme нет root (с использованием последней версии машинописного текста и материалов- ui), и к элементу form не применялся класс. Я попытался проследить за обсуждением выше, но это кажется безрезультатным. И действительно, в списке унаследованных классов отсутствовало сгенерированное имя класса для form . Если я добавил сгенерированное имя класса вручную (найдено в withStyles с помощью console.log(theme) в инструментах разработки, проверяет элементы, все в порядке, поэтому, очевидно, класс генерируется правильно. Не проходил через withStyles в form элемент

Итак, я вернулся к стилям, пока это не будет отсортировано:

<form style = {{display:'flex',flexWrap:'wrap'}} autoComplete="off">

@HenrikBechmann Вы пробовали следовать документации по стилям для машинописного текста? В прошлом мне это очень помогало. https://material-ui.com/guides/typescript/

Спасибо @lookfirst! Я просмотрел (хотя и не сначала :-)) этот документ и использовал

export default withStyles({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
})(BaseForm)

(передача объекта, а не функции)

... что позволило избежать ошибок машинописного текста и позволило внедрить сгенерированный класс.

Надеюсь, другие советы помогут с более сложными конструкциями.

Я также подтвердил, что более сложная структура для функции styles работает (вставляет сгенерированный className в form ):

import React from 'react'

import { withStyles, createStyles, Theme } from '@material-ui/core/styles'

/*
    patterned after first demo https://material-ui.com/demos/selects/ for 3.03
    use Typsecript fixes from here: https://material-ui.com/guides/typescript/
*/

const styles = (theme:Theme) => createStyles({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
})

class BaseForm extends React.Component<any,any> {

    render() {
        const { classes } = this.props

        return (
            <form className = {classes.root} autoComplete="off">
                {this.props.children}
            </form>
        )
    }
}

export default withStyles(styles)(BaseForm)

Изменить: @ eps1lon указал, что в этом нет необходимости с использованием WithStyles !

У меня был некоторый успех, используя ReturnType<T> чтобы сгенерировать для меня ClassKey :

import * as React from 'react';

import withStyles, {
  StyledComponentProps, 
  StyleRulesCallback,
} from '@material-ui/core/styles/withStyles';

import { Theme } from '@material-ui/core/styles/createMuiTheme';

const overrideStyles = (theme: Theme) => ({
  root: {
    display: 'flex',
    flexDirection: 'column',
  },
});

type Props = StyledComponentProps<keyof ReturnType<typeof overrideStyles>>;

class MyComponent extends React.PureComponent<Props> {
  render() {
    return <div className={this.props.classes.root}></div>;
  }
}

export default withStyles(overrideStyles as StyleRulesCallback, {withTheme: true})(MyComponent);

Использование keyof ReturnType<typeof styleOverrides> в качестве StyledComponentProps ClassKey предоставит вам ключи от объекта, возвращаемого overrideStyles и избавит вас от необходимости вести список этих ключей вручную. . Единственный сбой, который я заметил, - это ошибка типа, если я не использую overrideStyles as StyleRulesCallback в вызове withStyles . Я не уверен на 100%, почему. Я думаю, что withStyles почему-то не понимает, что такое overrideStyles .

Чтобы прояснить этот довольно сложный тип, typeof styleOverrides преобразуется в функцию, возвращающую объект стиля. ReturnType<T> предоставит вам сам объект стиля. keyof получит ключи от объекта стиля.

@chrislambe Вам следует руководством по ReturnType и т. Д. createStyles и WithStyles должно быть достаточно в качестве помощников.

@ eps1lon Ой, очень круто! Спасибо!

fwiw Мне все больше нравится пара createStyles / withStyles по мере того, как я их использую. Продвигает аккуратный код, занимается всеми моими проблемами стиля / машинописного текста, и если мне нужен локальный условный CSS, я просто создаю атрибуты локального стиля, которые, конечно, имеют приоритет над классами.

Отлично!!

Следуя руководству по машинописному тексту с @ material-ui / [email protected], я получаю Test does not have required attribute classes на:

import React from 'react'
import { Theme, WithStyles, withStyles, createStyles } from '@material-ui/core/styles'

const styles = (theme: Theme) => createStyles({
  root: {
    color: theme.palette.action.active
  },
})

interface Props extends WithStyles<typeof styles> {
  asd: boolean
}

class TestComponent extends React.Component<Props> {

  render() {
    const { classes } = this.props

    return (
      <div className={classes.root}>
      </div>
    )
  }
}

const Test = withStyles(styles)(TestComponent)

const a = () => <Test asd={true}/>

@ aaronlifton2
Пожалуйста, следите за дополнением

@valoricDe Решили проблему?

@TrejGun Я только что проверил. С функциональным компонентом и @ material-ui / [email protected] у меня этой проблемы нет

Я не совсем понимаю.
Следуя документам здесь: https://material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles
кажется, просто приводит к проблеме этой исходной проблемы. Когда вы где-то используете компонент, машинописный текст заставляет вас _пропустить_ свойство классов в качестве опоры вместо того, чтобы понимать, что оно будет _injection_ by withStyles.

Я читаю эти выпуски уже несколько часов и не совсем понимаю. Любая помощь была бы такой приятной на этом этапе.

Относительно этого предложения выше

@cfilipov при декорировании класса компонента вы должны использовать StyledComponentProps вместо WithStyles , а если в режиме строгой проверки типа вам нужно использовать ненулевой оператор утверждения ! для извлечения поля classes . Это компромисс, позволяющий использовать withStyles в качестве декоратора класса. Декораторы классов в TypeScript страдают от ограничения , заключающегося в

  1. не поддерживают использование withStyles в качестве декоратора класса
  2. требовать, чтобы вы передавали фиктивную опору classes при создании элемента декорированного типа компонента (предыдущий компромисс, который, возможно, был более раздражающим )
  3. требовать, чтобы classes считалось допускающим значение NULL внутри компонента, вынуждая вас использовать оператор ! при доступе к его полям ( текущий компромисс )

Я настоятельно рекомендую, чтобы, если ваш компонент не имеет состояния, вы использовали функциональный компонент без состояния, который потребует меньше аннотаций типов и будет более безопасным по типу:

export default withStyles(styles)<Props>(({ classes, message }) => (
  <div className={classes.main}>
    <div className={classes.foo}>
      Hello World! {message}
    </div>
  </div>
));

Как я узнал, как использовать StyledComponentProps ? Кажется, я просто передаю строки ключей, определенных в объекте стилей.

Но документы говорят нам сделать что-то, что просто не сработает? что мне не хватает? Мне бы хотелось использовать https://material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles ...

Это возможно?

@valoricDe , как вы сделали функциональный компонент, у которого не было этой проблемы

@TrejGun Я только что проверил. С функциональным компонентом и @ material-ui / [email protected] у меня этой проблемы нет

Я пробую что-то вроде этого:

`` импортировать React, {ChangeEvent, Component, Dispatch} из "реагировать";
импортировать PropTypes из "prop-types";
импортировать из "react-redux";
импортировать {сетку, FormControlLabel, Theme, createStyles, withStyles, Radio, WithStyles} из "@ material-ui / core";
Импортировать сумму из "./Amount";
импортировать {onPastDueFormFieldChange} из "../../store/actions/selectPaymentAmountActions";

const styles = (тема: Тема) =>
createStyles ({
количество: {
alignSelf: "центр",
},
});

интерфейс OwnProps расширяет WithStyles{}

interface StateProps {
pastDue ?: число;
pastDueOrTotalOrOther: строка;
}

interface DispatchProps {
onPastDueFormFieldChange: OnPastDueFormFieldChange;
}

введите Props = StateProps & DispatchProps & OwnProps;

const PastDueFormField = withStyles (стили) (
({классы, pastDue, pastDueOrTotalOrOther, onPastDueFormFieldChange}: Props) => (
значение = "pastDue"
проверено = {pastDueOrTotalOrOther === "pastDue"}
onChange = {onPastDueFormFieldChange}
label = "Просроченный:"
control = { }
/>




),
);

const mapStateToProps = (состояние: RootState): StateProps => ({
pastDue: state.customerData.balanceDue.pastDue,
pastDueOrTotalOrOther: state.customerPaymentsForm.pastDueTotalOrOther,
});

экспорт подключения по умолчанию(
mapStateToProps,
{onPastDueFormFieldChange},
) (PastDueFormField);

When I use this component I have this error:
```import PastDueFormField
Property 'classes' is missing in type '{}' but required in type 'Readonly<PropsWithChildren<Pick<Pick<Props, "pastDue" | "pastDueOrTotalOrOther" | "onPastDueFormFieldChange"> & StyledComponentProps<"amount">, "classes" | "innerRef"> & OwnProps>>'

@yehudamakarov Попробуйте react-redux и добавить connect когда все будет работать должным образом. Невероятно сложно получить хороший обзор, когда вводится пропеллер.

При столкновении с этими проблемами я

  1. сначала введите мои компонентные реквизиты
  2. проверьте, все ли требуется, как ожидалось, т.е. получите missing props
  3. применять hoc
  4. посмотреть, распознал ли машинописный текст каждую введенную опору
  5. повторить 3, пока не будут применены все hocs.

Это продвигает более чистый код. Особенно по порядку действий. В настоящее время вы смешиваете withStyles и connect без разделения задач.

Большое спасибо, Себастьян.
Я решил свою проблему, просто не передав общие аргументы для подключения. Я вынул кусок <StateProps ...> .

Я думаю, что эти общие аргументы мешали моему интерфейсу OwnProps, расширяющему WithStyles <>.

Поскольку я все равно передаю все компоненту, проверки типов, которую я получаю от Props, достаточно. Не уверен, зачем id нужны дженерики connect <>.

Спасибо!

Вот как бы выглядело "украшение" класса, если бы мы сделали правильную типизацию:

type NonStyleProps = {
  text: string
};

const styles = {
  root: {
    backgroundColor: 'red'
  }
};

const DecoratedComponent = withStyles(styles)(
  class extends React.Component<NonStyleProps & WithStyles<'root'>> {
    render() {
      return (
        <div className={this.props.classes.root}>
          {this.props.text}
        </div>
      );
    }
  }
);

А как добавлять темы (useTheme ()) внутрь вроде:

const decorate = withStyles((theme: Theme) => ({
  root: {
    display: "flex"
  },
  appBar: {
    zIndex: theme.zIndex.drawer + 1,
    transition: theme.transitions.create(["width", "margin"], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen
    })
  }
})
Была ли эта страница полезной?
0 / 5 - 0 рейтинги