Definitelytyped: 一部の既存の接続呼び出しは5.0.16で中断されます

作成日 2018年04月11日  ·  3コメント  ·  ソース: DefinitelyTyped/DefinitelyTyped

  • [x] @types/xxxxパッケージを使用しようとしましたが、問題が発生しました。
  • [x] tscの最新の安定バージョンを使用してみました。 https://www.npmjs.com/package/typescript
  • [x] StackOverflowに不適切な質問があります。 (そこで適切な質問をしてください)。
  • [x] [メンション](https://github.com/blog/821-mention-somebody-they-re-notified)著者( index.d.ts Definitions by:index.d.ts )応答。

    • 著者: @Pajn @tkqubo @thasner @kenzierocks @ clayne11 @tansongyang @NicholasBoll @mDibyo @pdeva

問題)

こんにちは! 5.0.16更新したところ、既存のプロジェクトでこれらの新しい型を使用するとすぐに問題が発生しました。 関連するバージョン番号は次のとおりです。

@types/react-redux: ^5.0.16,
typescript: ^2.8.x,
react-redux: ^5.0.5,

典型的なコンテナはコンパイルされません

これが私がコンパイルすべきだと思ういくつかのコードです(そしてそれは5.0.16前にコンパイルされ、バージョンを5.0.15戻すと再びコンパイルされます):

// components/exampleComponent.ts
import React = require('react')
import { IState, IDateRange, ReportType } from '../../types/index'

export interface IExampleProps {
  label?: string
  dateRange: IDateRange
  onDateRangeChange: (value: IDateRange) => void
}

export class ExampleComponent extends React.Component<IExampleProps> {
  // implementation
}
// containers/exampleComponent.ts
import { connect } from 'react-redux'
import { IState, IDateRange, ReportType } from '../../types/index'

interface IPropsFromState {
  dateRange: IDateRange
}

interface IPropsFromParent {
  reportType: ReportType
}

const mapStateToProps = (state: IState, props: IPropsFromParent): IPropsFromState => {
  const config = state.reporting.reportConfigs[props.reportType]

  return {
    dateRange: config ? config.dateRange : null,
  }
}

const connector = connect<IPropsFromState, null, IPropsFromParent>(
  mapStateToProps,
)

export const ExampleContainer = connector(ExampleComponent) // <-- this does not compile

通常はこのようなコンテナを使い続けますが、

<ExampleContainer reportType={ReportType.USERS_CREATED} />

ただし、このコードでは、最新の@types/react-redux5.0.16 、typescriptを2.8.1で使用すると、代わりに次のエラーが発生します。

[ts]
Argument of type 'typeof ExampleComponent' is not assignable to parameter of type 'ComponentType<IPropsFromState & DispatchProp<any> & IPropsFromParent>'.
  Type 'typeof ExampleComponent' is not assignable to type 'StatelessComponent<IPropsFromState & DispatchProp<any> & IPropsFromParent>'.
    Type 'typeof ExampleComponent' provides no match for the signature '(props: IPropsFromState & DispatchProp<any> & IPropsFromParent & { children?: ReactNode; }, context?: any): ReactElement<any>'.

5.0.16で導入された変更を調べると、 connector型がInferableComponentEnhancerWithProps<IPropsFromState & IPropsFromParent, IPropsFromParent>あるため、型システムが動揺しているように感じます。これは、最初の引数が型IPropsFromState & IPropsFromParentであると想定していることを意味します。 reportTypeがありません。

たとえば、私がこれを書いた場合:

const f = <P extends IPropsFromParent & IPropsFromState>(component: Component<P>) => { /**/ }
const g = <P extends IPropsFromParent & IPropsFromState>(props: P) => { /**/ }

const record: IExampleProps = null

f(ExampleComponent)
g(record)

これらの最小限の例は失敗します。 1つ目は、上記のコードと同じ理由で失敗し、同じ不透明なエラーメッセージが表示されます。 明らかに、 IExamplePropsはプロパティreportType: ReportTypeがないため、 IExamplePropsP割り当てることができないため、2番目は失敗します。 reportTypeがありません。 これが、内部的には、最初の例が失敗する原因になっているのではないかと思います。

5.0.16コンテナが、ラップされたコンポーネントのインターフェイスに新しいプロパティを追加することを許可されていないようです。 これは私がコードを見て見たものです。

コンポーネントを必要なプロパティのみで定義し、それらのコンポーネントをHOCで拡張して、新しいインターフェイスを定義し、reduxストアを介してコンポーネントにそのプロパティを提供することは私の通常のワークフローの一部です。 新しいインターフェイスがラップされたコンポーネントのインターフェイスのサブセットである場合もあれば、そうでない場合もあります。 上記の場合、新しいインターフェイスには、呼び出し元が使用する追加のプロパティreportTypeありますが、ラップされたコンポーネントには表示されません。


より特異なコンテナはコンパイルされません

この変更によって壊れた、私が使用するテクニックの別の例があります。

2つの単純なコンポーネントがあるとします。

class NameDateComponent extends React.PureComponent<{ name: string, date: string}> {}

class DateOnlyComponent extends React.PureComponent<{ date: string }> {}

nameプロパティについて何も知らなくても、これらのコンポーネントにdateを提供するHOCを構築したいと思います。 このようにして、たとえばNameProviderとDateProviderを作成し、次のように構成できます: NameProvider(DateProvider(BaseComponent))またはこのDateProvider(NameProvider(BaseComponent))ように、通常は適切に型指定されたコンポーネントでは実行できません。 TOwnPropsを指定する必要があるため、エンハンサー。

interface IWithDate {
  date: string
}

// ComponenProps defines a component interface that includes IWithDate
// NewAPI defines a new interface that excludes IWithDate
// so the types represent only what will change in the given component, without needing to know the rest of the interface
function DateProvider <ComponentProps extends IWithDate, NewAPI extends Minus<ComponentProps, IWithDate>> (Base: CompositeComponent<ComponentProps>) {

  const enhancer = connect<ComponentProps, null, NewAPI>(
    (_state: IState, props: NewAPI): ComponentProps => {
      // because of the 'never' type, 
      // typescript doesn't think NewAPI & IWithProps == ComponentProps
      // so we have to coerce this (but you and I can see that the above holds)
      const newProps: any = Object.assign({
        date: '2017-01-01'
      }, props)

      return newProps as ComponentProps
    },
    null
  )

  return enhancer(Base) // <-- after 5.0.16 this line does not compile
}

この新しいインターフェイスに依存しないコンポーネントエンハンサーは、次のように使用されます。

const NameOnly = DateProvider(NameDateComponent)
const Nothing = DateProvider(DateOnlyComponent)

.
.
.

<Nothing />
<NameOnly name='Bob' />
<NameDateComponent name='Bob' date='2017-01-01' />

したがって、 DateProvider HOCは、コンポーネントのインターフェイスを完全に認識していなくても、コンポーネントを拡張できます。 与えられたコンポーネントがそれが提供する小道具を受け入れることができることを知る必要があるだけです。

5.0.16使用すると、これは機能しなくなり、代わりに次のエラーメッセージが表示されます。

[ts]
Argument of type 'CompositeComponent<ComponentProps>' is not assignable to parameter of type 'ComponentType<ComponentProps & NewAPI>'.
  Type 'ComponentClass<ComponentProps>' is not assignable to type 'ComponentType<ComponentProps & NewAPI>'.
    Type 'ComponentClass<ComponentProps>' is not assignable to type 'StatelessComponent<ComponentProps & NewAPI>'.
      Types of property 'propTypes' are incompatible.
        Type 'ValidationMap<ComponentProps>' is not assignable to type 'ValidationMap<ComponentProps & NewAPI>'.
          Type 'keyof ComponentProps | keyof NewAPI' is not assignable to type 'keyof ComponentProps'.
            Type 'keyof NewAPI' is not assignable to type 'keyof ComponentProps'.
              Type 'keyof NewAPI' is not assignable to type '"date"'.

遊んでみると、次のことに気づきました。

interface IWithDate {
  date: string
}

interface IComponentProps {
  name: string
  date: string
}

// I've torn out the internals of the DateProvider above
const connect1 = <T extends IWithDate, U extends Omit<T, keyof IWithDate>>(base: CompositeComponent<T>) => {
  const enhancer: InferableComponentEnhancerWithProps<T & U, U> = () => null

  return enhancer(base) // <-- this is a compile error
}

const connect2 = <T extends IWithDate, U extends Omit<T, keyof IWithDate>>() => {
  const enhancer: InferableComponentEnhancerWithProps<T & U, U> = () => null

  return enhancer
}

const enhancer = connect2<IComponentProps, Omit<IComponentProps, keyof IWithDate>>()
const container = enhancer(NameDateComponent) // <-- this is not a compile error

コネクタを明示的に入力すると、すべてが機能しますか?


それでおしまい! 読んでくれてありがとう;)今のところ私は@types/react-reduxを以前のバージョンに設定しました、そしてすべてが順調です。

最も参考になるコメント

5.0.15に戻しても、問題は完全には解決しません。 5.0.15はこの種のコードを警告なしにコンパイルしますが、 connect呼び出しでプレゼンテーションコンポーネントの小道具のタイプチェックを追加すると、エラーが発生します。 (ラッピングコンポーネントにMyComponentはない小道具があると仮定します)

たとえば、これは5.0.15では機能しますが、5.0.16では機能しません。
connect(stateToProps, dispatchToProps)(MyComponent)

ただし、5.0.15でも、コンパイラエラーなしでMyComponent小道具をタイプチェックすることはできません。
connect<statetoprops, dispatchtoprops, mycomponentprops)(stateToProps, dispatchToProps)(MyComponent)
これにより、ラッピングコンポーネントの小道具がMyComponent存在しないというエラーが表示されます。

これは、 @ Pajnのクリーンアップによって

全てのコメント3件

@variousauthors使用している@types/react@types/react-reduxのバージョンを共有していただけますか?

編集: @物事を台無しにし、ライブラリの名前が表示されませんでした、申し訳ありません:失望しました:

@variousauthors私はあなたがこのコメントにスポットを当てていると思います

5.0.16以降、コンテナはラップされたコンポーネントのインターフェイスに新しいプロパティを追加できないように見えますか? これは私がコードを見て見たものです。

バグは、reduxのconnect関数の型定義がownPropsmapPropsToState交差することです。 これは、「コンテナ」コンポーネントは、派生した「プレゼンテーション」コンポーネントでその小道具を複製することを余儀なくされることを意味します。これは、一般的なreduxデザインパターンを壊します。

導入されたPR: https
その他の問題: https

5.0.15に戻しても、問題は完全には解決しません。 5.0.15はこの種のコードを警告なしにコンパイルしますが、 connect呼び出しでプレゼンテーションコンポーネントの小道具のタイプチェックを追加すると、エラーが発生します。 (ラッピングコンポーネントにMyComponentはない小道具があると仮定します)

たとえば、これは5.0.15では機能しますが、5.0.16では機能しません。
connect(stateToProps, dispatchToProps)(MyComponent)

ただし、5.0.15でも、コンパイラエラーなしでMyComponent小道具をタイプチェックすることはできません。
connect<statetoprops, dispatchtoprops, mycomponentprops)(stateToProps, dispatchToProps)(MyComponent)
これにより、ラッピングコンポーネントの小道具がMyComponent存在しないというエラーが表示されます。

これは、 @ Pajnのクリーンアップによって

このページは役に立ちましたか?
0 / 5 - 0 評価