Definitelytyped: @ types / reactのsetStateでのPickの䜿甚に぀いお

䜜成日 2017幎07月25日  Â·  53コメント  Â·  ゜ヌス: DefinitelyTyped/DefinitelyTyped

未定矩であっおはならないキヌに察しおundefinedを返すず、Reactによっおキヌが未定矩に蚭定されるため、 PickがsetStateのタむプに䜿甚されたこずを理解しおいたす。

ただし、 Pickず、他の問題が発生したす。 1぀は、コンパむラサヌビスのオヌトコンプリヌトは、オヌトコンプリヌトにPickの結果を䜿甚するため、圹に立たなくなりたす。コンプリヌトをリク゚ストするず、 Pickの結果にはただキヌが含たれおいたせん。オヌトコンプリヌトしたい。 しかし、コヌルバック匕数を䜿甚しおsetStateを曞き蟌む堎合、問題は特にひどいものです。

  1. キヌのリストは、最初のreturnステヌトメントから取埗されたす。 returnステヌトメントで特定のキヌを返さない堎合は、キヌのリストをneverにリセットせずに、匕数でそのキヌを読み取るこずもできたせん。 耇数のreturnステヌトメントが異なるキヌを返す堎合、特にどこかに未定矩のreturnがある堎合 if (state.busy) { return } 、蚘述が難しい堎合がありたす。

    • これは、垞にスプレッド this.setState(input => ({ ...input, count: +input.count + 1 })) で入力を䜿甚するこずで回避できたすが、 setStateがコヌルバックの戻り倀を枡すため、これは冗長であり、特に倧芏暡な状態では最適化が解陀されたす。 Object.assign 。

  2. 䜕らかの理由で、返す型が入力型ず互換性がない堎合、 Pickはキヌにneverを遞択し、関数は_anything_を返すこずができたす。 既存のキヌず䞀臎するキヌでさえ、倀ずしおanyを効果的に蚱可したす-それが適合しない堎合、それはPick edではなく、 {}超過プロパティずしお扱われたす
  3. neverがゞェネリック匕数ずしお遞択された堎合、䞊蚘の理由のいずれかにより、コヌルバック匕数は実際にはsetStateのオブゞェクト圢匏ぞの匕数ずしお扱われる可胜性がありたす。 これにより、コヌルバックの匕数は{}ではなくanyず入力されたす。 なぜこれが暗黙の゚ラヌではないのかわかりたせん。
interface State {
  count: string // (for demonstration purposes)
}

class Counter extends React.Component<{}, State> {
  readonly state: Readonly<State> = {
    count: '0'
  }

  render () {
    return React.createElement('span', { onClick: this.clicked }, this.state.count)
  }

  private readonly clicked = () => {
    this.setState(input => ({
      count: +input.count + 1 // not a type error
      // the setState<never>(input: Pick<State, never>) overload is being used
    }))
  }
}

芁玄するず、 Pick䜿甚するず、倚少の䞍䟿はありたすが、 setStateの非コヌルバック圢匏でタむプ゚ラヌをキャッチするのに圹立ちたすが、コヌルバック圢匏では完党に逆効果です。 ここでは、 undefinedを犁止するずいう意図されたタスクを実行しないだけでなく、コヌルバックの入力たたは出力での型チェックをたったく無効にしたす。

おそらく、少なくずもコヌルバックフォヌムでは、 Partialに倉曎する必芁があり、以前の定矩で行われたように、ナヌザヌがundefined倀を返さないこずを知っおいるこずを願っおいたす。

最も参考になるコメント

最近の「修正」により、 setState()コヌルバック内の耇数のreturnステヌトメントで問題が発生しおいたす。

Typescript2.6.2「strictFunctionTypes」を陀くすべおの「strict」オプションが有効になっおいる
タむプ/反応16.0.30

コヌド䟋

interface TestState {
    a: boolean,
    b: boolean
}

class TestComponent extends React.Component<{}, TestState> {
    private foo(): void {
        this.setState((prevState) => {
            if (prevState.a) {
                return {
                    b: true
                };
            }

            return {
                a: true
            };
        });
    }
}

コンパむラ゚ラヌ

error TS2345: Argument of type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }' is not assignable to parameter of type '((prevState: Readonly<TestState>, props: {}) => Pick<TestState, "b"> & Partial<TestState>) | (Pick<TestState, "b"> & Partial<TestState>)'.
  Type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }' is not assignable to type 'Pick<TestState, "b"> & Partial<TestState>'.
    Type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }' is not assignable to type 'Pick<TestState, "b">'.
      Property 'b' is missing in type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }'.

522         this.setState((prevState) => {
                          ~~~~~~~~~~~~~~~~

党おのコメント53件

ご意芋をいただきありがずうございたす。 これはあなたが提起する非垞に興味深い事䟋です。

意芋を述べる前に、その圱響に぀いお少し考える必芁がありたす。

ある時点で、 @ ahejlsbergはオプションを| undefinedずは異なる方法で扱いたいず考えおいたした。 したがっお、 foo?: stringは、fooが蚭定されおいないか、文字列であるこずを意味したす。

プロパティ倀を読み取る堎合、その差は99.9の確率で無関係ですが、曞き蟌みの堎合、特にPartial<>堎合、区別は非垞に重芁です。

残念ながら、これは重倧な蚀語倉曎であるため、3.0を埅぀か、フラグの埌ろに眮く必芁がありたす。

私たちが倉曎を蚀ったずしたら、 Partial<>は、その䜿甚を䞀目で拒吊するずいう私の珟圚の教矩の代わりに、倚くの人にずっお非垞に圹立぀ようになりたす。

@ahejlsbergあなたが忙しい人だず知っおいたすが、実装するのはどれほど難しいでしょうか undefinedが暗黙の割り圓お可胜な倀ではないように

さお、今朝しばらく時間をかけお問題に぀いお考えた埌、あなたが提案した問題に察するいく぀かの「解決策」があり、それぞれにかなり重い副䜜甚がありたす。

1.オプション interface State { foo?: string } を文字列を意味するか、蚭定されおいないものに倉曎したす。

䟋

interface State {
  foo: string;
  bar: string;
}

const bleh: Partial<State> = { foo: "hi" }; // OKAY
const bleh: Partial<State> = { foo: undefined; } // BREAK

これにより、技術的に問題が解決され、 Partial<>を䜿甚できるようになりたすが、98のケヌスはより困難になりたす。 これは䞖界を壊すので、3.xたで実際に行うこずはできたせん。䞀般に、未蚭定ず未定矩の区別を実際に気にするラむブラリ/ナヌスケヌスはほずんどありたせん。

2.パヌシャルに切り替えるだけです

䟋

interface State {
  foo: string;
  bar: string;
}

setState(prevState => {foo: "hi"}); // OKAY
setState(prevState => {foo: undefined}); // OKAY BUT BAD!

3.䜕もしない

䟋

interface State {
  foo: string;
  bar: string;
}

// The following errors out because {foo: ""} can't be assigned to Pick<State, "foo" | "bar">
// Same with {bar: "" }
setState((prevState) => {
  if (randomThing) {
    return { foo: "" };
  }
  return { bar: "" };
});

// A work around for the few places where people need this type of thing, which works
setState((prevState) => {
  if (randomThing) {
    return { foo: "" } as State
  }
  return { bar: "" } as State
});

// This is fine because the following is still an error
const a = {oops: ""} as State

4.結合されるリテラル型にネストされたロゞックを远加したす

珟圚、耇数のリタヌンパスがある堎合、コンパむラはすべおの朜圚的なキヌを1぀の巚倧なPick<State, "foo" | "bar">たずめたす。

ただし、䞋䜍互換性のある倉曎は、 Pick<State, ("foo") | ("bar")>たたはより耇雑な堎合 Pick<State, ("foo" | "bar") | ("baz")>ように、リテラルをグルヌプ化できるようにするこずです。

芪の欠劂は、既存の機胜である倀の単䞀のセットを瀺唆しおいたす。

{foo: number}をPick<State, ("foo") | ("bar")>にキャストしようずするず、成功する可胜性がありたす。 {bar: number}ず同じです。

Pick<State, ("foo") | ("bar")>は、 Partial<State>および{foo: number} | {bar: number}もキャストできたす。

私の個人的な結論

1ず2は実行できたせん。 1぀は、䜕があっおもほがすべおの人に耇雑さをもたらし、もう1぀は、コンパむルするが明らかに正しくないコヌドを䜜成するのに圹立ちたす。

3は今日完党に䜿甚可胜であり、 setStateの関数に朜圚的な戻り倀ずしお| Sを远加した理由を思い出せたせんが、他の理由を掚枬するこずはできたせん。

4は3の回避策を取り陀くこずができたすが、TypeScript開発者次第であり、@ ahejlsbergに十分な関心を持っおもらうず、遅かれ早かれそれを芋るこずができるかもしれたせん。

これにより、タむプを倉曎した堎合よりも、今日のタむプの方が正しいず思いたす。

「䜕もしない」アプロヌチの問題は、実際に実際の型゚ラヌが発生した堎合に、コンパむラヌが蚘述したずおりに動䜜しないこずです。 たずえば、䟋を倉曎しお、倀を空の文字列ではなく0に蚭定した堎合

interface State {
  foo: string;
  bar: string;
}

// The following does not error at all because the compiler picks `Pick<State, never>`
// The function overload of `setState` is not used -- the object overload is, and it
// accepts the function as it is accepting anything (`{}`).
setState((prevState) => {
  if (randomThing) {
    return { foo: 0 };
  }
  return { bar: 0 };
});

今芋えたす。 ふりだしに戻る。 これに察する賢い解決策を䜜成できるかどうかを確認したす。 思い぀かない堎合は、提案するPartial<>゜リュヌションを評䟡する必芁がありたす。 考慮すべき重芁なこずは、倀の予期しないundefinedが、予期しない間違ったタむプよりも䞀般的/煩わしいものになるかどうかです。

明確にするために、これには2぀のオヌバヌロヌドがありたす...

setState<K extends keyof S>(f: (prevState: Readonly<S>, props: P) => Pick<S, K>, callback?: () => any): void;
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;

蚭定のいずれか、たたはこれらの䞡方のPartial<S>の代わりにPick<S, K>あなたの問題を解決するdoesntの。 それでもオブゞェクトバヌゞョンにドロップスルヌしたすが、䜕らかの理由で間違ったタむプを受け入れたす。

`` `ts
むンタヌフェむスの状態{
バヌ文字列;
foo番号;
}

クラスFooはReact.Component <{}、State> {を拡匵したす
public blah{
this.setStateprevState=>{bar1}; //゚ラヌはありたせん/
}
} `` `

extends objectを䜿甚しお、関数を匷制的に拒吊するこずはできたすか
制玄
金、2017幎7月28日に0:00゚リック・アンダヌ゜ン[email protected]は曞きたした

明確にするために、これには2぀のオヌバヌロヌドがありたす...

setStatefprevState読み取り専甚、小道具P=>ピック、コヌルバック=>任意void; setState状態ピック、コヌルバック=>任意void;

これらのいずれかたたは䞡方をPickではなくPartial
それはただオブゞェクトバヌゞョンにドロップスルヌしたす、䜕らかの理由で間違ったタむプを受け入れたす

むンタヌフェむスの状態{
バヌ文字列;
foo番号;
}
クラスFooはReact.Component <{}、State> {を拡匵したす
public blah{
this.setStateprevState=>{bar1}; //゚ラヌはありたせん/
}
} `` `

—
スレッドを䜜成したため、これを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-318388471 、
たたはスレッドをミュヌトしたす
https://github.com/notifications/unsubscribe-auth/AAEdfeEJ_Ejfana14fRII1OZuS7qTuyuks5sSKX3gaJpZM4OiDrc
。

やっおみたした。 関数はオブゞェクトです。

゚リックLアンダヌ゜ン
私のiPhoneから送信された

私はここに関連する問題を報告するために来たした。それは、状態タむプのリファクタリングがこの倉曎で壊れおいるずいうこずです。

たずえば、 https//github.com/tomduncalf/react-types-issue/blob/master/Test.tsxを参照しおsomethingをリファクタリング/名前倉曎する堎合https://github.com/tomduncalf/react-types-issue/blob/master/Test.tsx#L6、その行ずhttps://github.com/tomduncalf/react-types-issue/を曎新しhttps//github.com/tomduncalf/react-types-issue/blob/master/Test.tsxのsetState呌び出しでこれを䜿甚できたせん。 L20

正しく機胜させるために私が芋぀けた唯䞀の方法は、 setState呌び出すずきにオブゞェクトas IStateを明瀺的に入力するこずです。これは少し䞍䟿で、忘れがちです。

私は倉曎の論理的根拠を正確に理解しおいたせんが、状態を操䜜するずきにかなり重芁な方法で型安党性を砎ったようですので、それを解決する方法があれば玠晎らしいでしょう

ありがずう、
トム

ええ、繰り返したすが、 Partialを䜿甚するず、その関係情報がより適切に保たれるので、䜿甚したほうがよいず思いたす。

間違いなく、 Pickが正しくリファクタリングされないこずは、リファクタリングコヌドの制限/バグであり、改善される可胜性がありたすが、 Pickがhttps//の型安党性を提䟛しおいるずはただ信じおいたせんPartialはundefined Partialを蚱可したすが、 undefinedは想定されおいないため、ナヌザヌはそれを行わないように泚意する必芁がありたすが、 Pickは䜕でも蚱可しPickが代わりに空のむンタヌフェむスを生成したす。これは䜕でも受け入れたす。

https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment -318388471に関しおは、これは超過プロパティチェッカヌのバグである可胜性がありたすか それずも、2.3たたは2.4で超過プロパティチェッカヌが厳しくなる前にこれがテストされたしたか忘れたした

ここで気付いたもう1぀の問題は、コンポヌネントに状態タむプがない堎合぀たり、 React.Componentぞのタむプパラメヌタヌが1぀しかない堎合、たたは状態タむプが空の堎合 {} 、Typescriptで匕き続き蚱可されるこずです。゚ラヌをスロヌせずにsetStateを呌び出すず、私には正しくないようです–https//github.com/tomduncalf/react-types-issue/blob/master/Test2.tsxを参照しお

パヌシャルサりンドを䜿甚した゜リュヌションは、私よりも望たしいです。自分でパッチを適甚しお、どのように機胜するかを確認するこずもできたす。

ありがずう、
トム

こんにちは、みんな
理由はわかりたせんが、 setState宣蚀を単䞀の宣蚀に結合するず、次のようになりたす。

setState<K extends keyof S>(state: ((prevState: Readonly<S>, props: P) => Pick<S, K>) | Pick<S, K>, callback?: () => any): void;

それは私にずっお期埅通りに機胜したす

import * as React from 'react';

export class Comp extends React.Component<{}, { foo: boolean, bar: boolean }> {
  public render() {
    this.handleSomething();
    return null;
  }

  private handleSomething = () => {
    this.setState({ foo: '' }); // Type '""' is not assignable to type 'boolean'.
    this.setState({ foo: true }); // ok!
    this.setState({ foo: true, bar: true }); // ok!
    this.setState({}); // ok!
    this.setState({ foo: true, foo2: true }); // Object literal may only specify
    // known properties, and 'foo2' does not exist in type
    this.setState(() => ({ foo: '' })); // Property 'foo' is missing in type '() => { foo: string; }'.
    this.setState(() => ({ foo: true })); // ok!
    this.setState(() => ({ foo: true, bar: true })); // ok!
    this.setState(() => ({ foo: true, foo2: true })); // Property 'foo' is missing in type
    // '() => { foo: true; foo2: boolean; }'
    this.setState(() => ({ foo: '', foo2: true })); // Property 'foo' is missing in
    // type '() => { foo: string; foo2: boolean; }'.
    this.setState(() => ({ })); // ok!
  };
}

これは元の問題を修正するのに十分に倉曎できたすか

@mctepいい

そしお、私があなたのしたこずを少し拡匵しお、堎所によっおはPick<S, K>ではなくPartial<S> & Pick<S, K>になるず、むンテリセンスはあなたにキヌ名を提案したす。 残念ながら、キヌ名はプロパティ倀が「䜕か|未定矩」であるず蚀っおいたすが、それをコンパむルするず、よりよくわかりたす。

declare class Component<P, S> {
    setState<K extends keyof S>(state: ((prevState: Readonly<S>, props: P) => (Partial<S> & Pick<S, K>)) | (Partial<S> & Pick<S, K>), callback?: () => any): void;
}

interface State {
    foo: number;
    bar: string;
    baz?: string;
}

class Foo extends Component<{}, State> {
    constructor() {
        super();
        this.setState(() => { // error
            return {
                foo: undefined
            }
        });
        this.setState({ // error
            foo: undefined
        })
        this.setState({
            foo: 5,
            bar: "hi",
            baz: undefined
        })
    }
}

この倉曎は今日の埌半に行いたす

最近の「修正」により、 setState()コヌルバック内の耇数のreturnステヌトメントで問題が発生しおいたす。

Typescript2.6.2「strictFunctionTypes」を陀くすべおの「strict」オプションが有効になっおいる
タむプ/反応16.0.30

コヌド䟋

interface TestState {
    a: boolean,
    b: boolean
}

class TestComponent extends React.Component<{}, TestState> {
    private foo(): void {
        this.setState((prevState) => {
            if (prevState.a) {
                return {
                    b: true
                };
            }

            return {
                a: true
            };
        });
    }
}

コンパむラ゚ラヌ

error TS2345: Argument of type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }' is not assignable to parameter of type '((prevState: Readonly<TestState>, props: {}) => Pick<TestState, "b"> & Partial<TestState>) | (Pick<TestState, "b"> & Partial<TestState>)'.
  Type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }' is not assignable to type 'Pick<TestState, "b"> & Partial<TestState>'.
    Type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }' is not assignable to type 'Pick<TestState, "b">'.
      Property 'b' is missing in type '(prevState: Readonly<TestState>) => { b: true; } | { a: true; }'.

522         this.setState((prevState) => {
                          ~~~~~~~~~~~~~~~~

この倉曎の結果ずしお@UselessPicklesによっお説明された問題も確認できたす。

私はそれが垞に問題であったこずをかなり確信しおいたす。

私はそれが垞に問題であるずは限らないこずをかなり確信しおいたす。 setState()コヌルバックに耇数のreturnステヌトメントがあり、2か月以䞊問題なくコンパむルされおいるプロゞェクトがありたす。 私は2週間ごずにNPM䟝存関係のアップグレヌドに远い぀いおきたしたが、このコンパむラ゚ラヌは、types / reactの最新バヌゞョンにアップグレヌドした埌の今日から発生し始めたした。 以前のバヌゞョンでは、このコンパむラ゚ラヌは発生したせんでした。

パヌシャルからピックに倉曎されお以来、問題が発生しおいたす。 回避策は、返す予定のキヌのリストをsetStateの汎甚パラメヌタヌに指定するこずですが、その堎合は垞にすべおのキヌを返す必芁がありたす...

そのような堎合に私が行うこずは、倉曎されおいないキヌをkey: prevState.keyに蚭定しお、垞にすべおのキヌを返すか、prevState { ...prevState, newKey: newValue } でスプレッドを返すこずです。

たぶん、私は実際に、以前は偶然に機胜しおいた、より具䜓的な゚ッゞケヌスをコヌドに持っおいたすか 私のプロゞェクトの実際の䟋は次のようなもので、空のオブゞェクトを返すか状態を倉曎しないため、空でないオブゞェクトを返したす。

interface TestState {
    a: boolean,
    b: boolean
}

class TestComponent extends React.Component<{}, TestState> {
    private foo(newValue: boolean): void {
        this.setState((prevState) => {
            if (prevState.a === newValue) {
                // do nothing if there's no change
                return { };
            }

            return {
                a: newValue,
                // force "b" to false if we're changing "a"
                b: false
            };
        });
    }
}

return nullずreturn undefinedも、状態を倉曎しない堎合の完党に蚱容可胜な戻り倀です Object.assignを通過するため、 this.stateは倉曎されたせん。

私に思い出させおください、珟圚の眲名はそれらのどちらも蚱可しおいたせん。 nullは、少なくずもreturnを誀っお忘れおしたう可胜性があるものではないため、戻り倀ずしお蚱可する必芁がありたす。


ずにかく、眲名があいたいな堎合、TypeScriptは゜ヌス順で最初のreturnステヌトメントのみを遞択し、それを䜿甚しおゞェネリックパラメヌタヌを導出するようです。 単玔なゞェネリック ArrayやPromise の型をマヌゞできるようですが、コンテキスト型がPickようなマップ型の堎合は、それらをマヌゞするこずはありたせん。

最新のタむプの非機胜バヌゞョンでいく぀かのリグレッションが発生しおいたす。 特に、匕数を枡すずきの「状態」匕数タむプは次のように倉曎されたした。

setState状態ピック、コヌルバック=>任意void;

に

状態prevStateReadonly \ 、propsP=>Pick Partial \ |

https://github.com/DefinitelyTyped/DefinitelyTyped/commit/62c2219a6ed6dc34ea969b8c2c87a41d31002660#diff -96b72df8b13a8a590e4f160cbc51f40c

& Partial<S>の远加は、以前は機胜しおいたものを壊しおいるようです。

最小限の再珟は次のずおりです。

export abstract class ComponentBaseClass<P, S = {}> extends React.Component<P, S & { baseProp: string }>
{
    foo()
    {
        this.setState( { baseProp: 'foobar' } );
    }
}

これぱラヌで倱敗したす

429,18タむプ '{baseProp "foobar";の匕数 } 'はタむプ'のパラメヌタに割り圓おるこずができたせんprevState読み取り専甚タむプ '{baseProp "foobar";}'はタむプ 'Pick  PartialType 'に割り圓おるこずができたせん

状態タむプをS &{ baseProp: string }から{ baseProp: string }に倉曎するず、゚ラヌもなくなりたすただし、Sタむプを指定する実際のクラスは砎損したす。

それは面癜い。 倉曎の䞀郚をロヌルバックしお、䞀郚を遞択できたす。

私はあなたが報告するこずはTSのバグのように聞こえるず蚀いたす、具䜓的には

タむプ '{baseProp "foobar"; } 'はタむプ' Partialに割り圓おるこずができたせん

倧䞈倫。 SずbasePropの間に関係がないため、TSは䜕が起きおいるのかわからないかもしれたせん。

タむプ{ basePropnumber }のSを枡すこずができたす。その堎合、basePropに文字列を割り圓おるこずはできたせん。

おそらく、SがbasePropバヌゞョンを拡匵した堎合はどうでしょうか。

私は以前にこのようなこずを詊したした

interface BaseState_t
{
    baseProp: string
}

export abstract class ComponentBaseClass<P, S extends BaseState_t> extends React.Component<P, S >
{
    foo()
    {
        this.state.baseProp;
        this.setState( { baseProp: 'foobar' } );
    }
}

アクセスは正垞ですが、setState呌び出しにも同じ゚ラヌがありたす。

タむプの匕数 '{baseProp "foobar"; } 'はタむプ'のパラメヌタに割り圓おるこずができたせんprevStateReadonly \ 、propsP=> Pick Partial \ |
} 'はタむプ' Pick Partial \ 'に割り圓おるこずはできたせんタむプ '{baseProp "foobar";

それを構造化するのはおそらく良い方法ではありたせん-結局のずころ、䞀郚の子クラスは、基本クラスの倉数ず衝突した状態倉数を宣蚀する可胜性がありたす。 したがっお、typescriptは、そこで䜕が起こるかわからないず䞍平を蚀うのが正しいかもしれたせん。 しかし、それらの小道具にアクセスするこずに問題がないのは奇劙です。

うヌん。 これは間違いなくTSのバグのように感じたす。

今日はこれで遊んで、おそらくPartialを取り出したす。

これもテストケヌスずしお远加し、むンテリセンスを幞せにするための別のアむデアを詊しおみたす

やあ、
ここで同じ問題...

export interface ISomeComponent {
    field1: string;
    field2: string;
}

interface SomeComponentState {
    field: string;
}

export class SomeComponent<
    TProps extends ISomeComponent = ISomeComponent,
    TState extends SomeComponentState = SomeComponentState> extends React.Component<TProps, TState>{

    doSomething() {
        this.setState({ field: 'test' });
    }

    render() {
        return (
            <div onClick={this.doSomething.bind(this)}>
                {this.state.field}
            </div>
        );
    }
}

setStateの゚ラヌ
TS2345 (TS) Argument of type '{ field: "test"; }' is not assignable to parameter of type '((prevState: Readonly<TState>, props: TProps) => Pick<TState, "field"> & Partial<TState>) | (Pick...'. Type '{ field: "test"; }' is not assignable to type 'Pick<TState, "field"> & Partial<TState>'. Type '{ field: "test"; }' is not assignable to type 'Partial<TState>'.

この倉曎埌、゚ラヌが発生し始めたした。 バヌゞョン16.0.10では正垞に動䜜したした。

Typescriptにはいく぀かの関連する問題があり、蚭蚈どおりに機胜するようにそれらを閉じたした。

https://github.com/Microsoft/TypeScript/issues/19388

ここでいく぀かの䟋の芁点を䜜成したした https 

動䜜はただ奇劙に芋えたすが。 特に、キャストなしで基本クラスずしお型指定された倉数に割り圓おお、問題なく同じ呌び出しを行うこずができたす。 この問題は、割り圓おず比范が2぀の異なるものであるこずを瀺唆しおいるようです。

あなたたちを忘れおいたせん。 すぐに修正されたす

参照されたPRはこの問題を解決するはずです。 たた、この゚ッゞケヌスを再び壊さないように保護するテストを远加したした。

@ericanderson迅速な察応に感謝したす:)

新しい修正には制限/欠点がありたすか

私が珟圚知っおいるものはありたせん。 むンテリセンスを維持するこずができたしたいく぀かの゚ッゞケヌスを解決するため、実際には以前よりも優れおいたす。

詳述するず、 & Partial<S>解決策は、むンテリセンスをだたしお可胜なパラメヌタを明らかにするこずでしたが、それはX | undefinedず述べるこずによっお行われたした。 もちろんこれはコンパむルに倱敗したすが、少し混乱したした。 | S取埗するず、むンテリセンスが修正され、すべおの正しいパラメヌタヌが提案され、誀ったタむプが衚瀺されなくなりたす。

setStateコヌルバックからの可胜な戻り倀ずしおnullを远加するこずを怜蚎したした return;を䜜成せずに、状態を倉曎したくない状態に戻すこずができるものたた有効ですが、代わりに型掚論を完党に攟棄し、キヌずしおneverたした😢

今のずころ、実際に状態の曎新をスキップしたいコヌルバックでは、 return null!たす。 この戻り倀のnever型により、TypeScriptはゞェネリック型掚論の戻り倀を無芖したす。

こんにちは、みんな...

最埌のコミットで問題が修正されたした。
迅速な返答に感謝臎したす 

どのバヌゞョンで修正されおいたすか npmに公開されおいたすか @UselessPicklesが芋぀かったように、setStateのコヌルバックバヌゞョンが戻り倀にプロパティの䞍䞀臎があるず蚀っおいる堎合がありたす。

最新の@types / reactで良いはずです

15シリヌズず16シリヌズで修正したした

import produce from 'immer';

interface IComponentState
{
    numberList: number[];
}

export class HomeComponent extends React.Component<ComponentProps, IComponentState>

Reactの叀い型の定矩。

// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
// Also, the ` | S` allows intellisense to not be dumbisense
setState<K extends keyof S>(
    state: ((prevState: Readonly<S>, props: P) => (Pick<S, K> | S)) | (Pick<S, K> | S),
    callback?: () => void
): void;

..この゚ラヌが発生したす

screen shot 2018-05-18 at 2 36 44 pm

私はこの提案を詊したした

setState<K extends keyof S>(
    state:
        ((prevState: Readonly<S>, props: P) => (Partial<S> & Pick<S, K>))
        | (Partial<S> & Pick<S, K>),
    callback?: () => any
): void;

Intellisenseは、Reactの状態からプロパティを怜出できるようになりたした。 ただし、怜出されたプロパティはpossibly undefinedずしお認識されるようになりたした。

screen shot 2018-05-18 at 2 37 32 pm

numberListが未定矩でもnull蚱容でもない堎合でも、nullアサヌション挔算子を䜿甚する必芁がありたす。

screen shot 2018-05-18 at 2 38 51 pm

タむプセンシングが改善されるたで、叀いタむプ定矩のたたにしおおきたす。 それたでの間、むマヌプロデュヌスのゞェネリックパラメヌタヌのタむプを明瀺的に説明したす。 produce<IComponentState>は、 list!よりも掚論が簡単です。

screen shot 2018-05-18 at 2 51 43 pm

最初の゚ラヌは、䜕も返さないためです。 それはsetStateがどのように機胜するかではありたせん。

蟲産物で倉数を返さない堎合でも機胜したす。 私はここの䟋TypeScript以倖に埓いたした

https://github.com/mweststrate/immer

onBirthDayClick2 = () => {
    this.setState(
        produce(draft => {
            draft.user.age += 1
            // no need to return draft
        })
    )
}

TypeScriptがそのコヌドを実行できないようにする唯䞀のこずは、React型定矩から誀っお型が掚枬されおいるこずです。 タむプ定矩はnumberList does not exist on type Pick<IComponentState, never>゚ラヌを報告したす。 生成物のゞェネリックパラメヌタヌ、぀たりproduce<IComponentState>型を明瀺的に枡すこずで、コンパむル゚ラヌをなくすこずができたす。

蟲産物で倉数を返しお、React型定矩が型を掚枬するのに圹立぀かどうかを確認しようずしたしたがひよこず卵の問題です、それでもReact型定矩が状態の正しい型を怜出する方法はありたせん。 したがっお、ドラフトのむンテリセンスは衚瀺されたせん。

screen shot 2018-05-18 at 10 38 04 pm

あるいは、コンパむラからの期埅が間違っおいるかもしれたせん:)コンパむラはコヌドを裏返しに凊理するため、setStateの型に基づいおドラフト倉数の型を䜜成できたせん。 しかし、提案された型定矩は、コンパむラが倖郚からコヌドを凊理でき、倖郚コヌド setState から内郚コヌド produce に枡すこずができる最適な型を遞択できるず私に思わせたした。

setState<K extends keyof S>(
    state:
        ((prevState: Readonly<S>, props: P) => (Partial<S> & Pick<S, K>))
        | (Partial<S> & Pick<S, K>),
    callback?: () => any
): void;

䞊蚘の型定矩を䜿甚するず、コンパむラはドラフトにnumberListプロパティがあるこずを怜出できたす。 ただし、 possibly undefinedずしお怜出されたす。

image

さらにいじくり回すず、setStateの型定矩にSを远加するこずで、コンパむラが状態の型を枡しおドラフトを生成できるようにしたした。

setState<K extends keyof S>(
    state:
        ((prevState: Readonly<S>, props: P) => (Partial<S> & Pick<S, K> & S))
        | (Partial<S> & Pick<S, K>),
    callback?: () => any
): void;

コヌドは珟圚コンパむル䞭です:)

screen shot 2018-05-18 at 11 21 03 pm

゚ラヌはsetStateではなく、蟲産物の内郚にありたす。 蟲産物のタむプ定矩は䜕ですか

䞊蚘の私のPRは、DefinitelyTypedのテストスクリプトで゚ラヌが発生したした。ロヌカルでテストしたせんでした。 だから私は今それをロヌカルでテストしおいたす。

これがむマヌ/プロデュヌスタむプの定矩です。

/**
 * Immer takes a state, and runs a function against it.
 * That function can freely mutate the state, as it will create copies-on-write.
 * This means that the original state will stay unchanged, and once the function finishes, the modified state is returned.
 *
 * If the first argument is a function, this is interpreted as the recipe, and will create a curried function that will execute the recipe
 * any time it is called with the current state.
 *
 * <strong i="7">@param</strong> currentState - the state to start with
 * <strong i="8">@param</strong> recipe - function that receives a proxy of the current state as first argument and which can be freely modified
 * <strong i="9">@param</strong> initialState - if a curried function is created and this argument was given, it will be used as fallback if the curried function is called with a state of undefined
 * <strong i="10">@returns</strong> The next state: a new state, or the current state if nothing was modified
 */
export default function<S = any>(
    currentState: S,
    recipe: (this: S, draftState: S) => void | S
): S

// curried invocations with default initial state
// 0 additional arguments
export default function<S = any>(
    recipe: (this: S, draftState: S) => void | S,
    initialState: S
): (currentState: S | undefined) => S
// 1 additional argument of type A
export default function<S = any, A = any>(
    recipe: (this: S, draftState: S, a: A) => void | S,
    initialState: S
): (currentState: S | undefined, a: A) => S
// 2 additional arguments of types A and B
export default function<S = any, A = any, B = any>(
    recipe: (this: S, draftState: S, a: A, b: B) => void | S,
    initialState: S
): (currentState: S | undefined, a: A, b: B) => S
// 3 additional arguments of types A, B and C
export default function<S = any, A = any, B = any, C = any>(
    recipe: (this: S, draftState: S, a: A, b: B, c: C) => void | S,
    initialState: S
): (currentState: S | undefined, a: A, b: B, c: C) => S
// any number of additional arguments, but with loss of type safety
// this may be alleviated if "variadic kinds" makes it into Typescript:
// https://github.com/Microsoft/TypeScript/issues/5453
export default function<S = any>(
    recipe: (this: S, draftState: S, ...extraArgs: any[]) => void | S,
    initialState: S
): (currentState: S | undefined, ...extraArgs: any[]) => S

// curried invocations without default initial state
// 0 additional arguments
export default function<S = any>(
    recipe: (this: S, draftState: S) => void | S
): (currentState: S) => S
// 1 additional argument of type A
export default function<S = any, A = any>(
    recipe: (this: S, draftState: S, a: A) => void | S
): (currentState: S, a: A) => S
// 2 additional arguments of types A and B
export default function<S = any, A = any, B = any>(
    recipe: (this: S, draftState: S, a: A, b: B) => void | S
): (currentState: S, a: A, b: B) => S
// 3 additional arguments of types A, B and C
export default function<S = any, A = any, B = any, C = any>(
    recipe: (this: S, draftState: S, a: A, b: B, c: C) => void | S
): (currentState: S, a: A, b: B, c: C) => S
// any number of additional arguments, but with loss of type safety
// this may be alleviated if "variadic kinds" makes it into Typescript:
// https://github.com/Microsoft/TypeScript/issues/5453
export default function<S = any>(
    recipe: (this: S, draftState: S, ...extraArgs: any[]) => void | S
): (currentState: S, ...extraArgs: any[]) => S
/**
 * Automatically freezes any state trees generated by immer.
 * This protects against accidental modifications of the state tree outside of an immer function.
 * This comes with a performance impact, so it is recommended to disable this option in production.
 * It is by default enabled.
 */
export function setAutoFreeze(autoFreeze: boolean): void

/**
 * Manually override whether proxies should be used.
 * By default done by using feature detection
 */
export function setUseProxies(useProxies: boolean): void

@ericandersonがPartial代わりにPickが䜿甚される理由に぀いおの議論を教えおいただけたすか これは私に䜕時間もの悲しみを匕き起こしたしたコヌルバックバヌゞョンではなく、プレヌンなsetState(obj)を䜿甚したす、そしお今のずころ私は回避策ずしおthis.setState(newState as State)を䜿甚したす。 䜕かが足りないので、なぜ倉曎されたのかを理解したいだけです。

こんにちは@ericanderson 、

最新の定矩に問題がありたす。

私のナヌスケヌスは簡単に次のようになりたす。

interface AppState {
  valueA: string;
  valueB: string;
  // ... something else
} 
export default class App extends React.Component <{}, AppState> {
  onValueAChange (e:React.ChangeEvent<HTMLInputElement>) {
    const newState: Partial<AppState> = {valueA: e.target.value}
    if (this.shouldUpdateValueB()) {
      newState.valueB = e.target.value;
    }
    this.setState(newState); // <-- this leads to a compiling error
  }
  // ... other methods
}

゚ラヌメッセヌゞは次のようなものです。

Argument of type 'Partial<AppState>' is not assignable to parameter of type 'AppState | ((prevState: Readonly<AppState>, props: {}) => AppState | Pick<AppState, "valueA" | "v...'.
  Type 'Partial<AppState>' is not assignable to type 'Pick<AppState, "valueA" | "valueB" | "somethingElse">'.
    Types of property 'valueA' are incompatible.
      Type 'string | undefined' is not assignable to type 'string'.
        Type 'undefined' is not assignable to type 'string'.

Partial<AppState>はsetState眲名ず互換性がないようです。 もちろん、私は次のようなタむプアサヌションによっおこれを解決できたす

this.setState(newState as Pick<AppState, 'valueA' | 'valueB'>)

しかし、それは理想的ではありたせん。理由は次のずおりです。
1この構文は非垞に冗長です
2さらに重芁なこずに、型アサヌションは私の実際のデヌタに違反する可胜性がありたす。 たずえば、 newState as Pick<AppState, 'somethingElse'>もチェックに合栌したすが、私のデヌタには適合したせん。

郚分的だず思いたすどういうわけかピックず互換性があるはずです、郚分的なのでTから䞍確かな数のキヌを遞択するだけです。正確かどうかはわかりたせん。 ずにかく、私の芳点からの理想的な䜿甚法は、Partial型の倉数を枡すこずができるずいうこずです。setStateに盎接。

私の提案を怜蚎したり、誀解がある堎合は指摘しおいただけたせんか。 ありがずうございたした

これは最初は本圓に叀い倉曎です。 したがっお、他の誰かが最近これを倉曎しない限り、おそらく間違った朚を吠えおいるでしょう。

そうは蚀った。 郚分的には未定矩の倀を蚱可したす。

const aPartial <{foostring}> = {fooundefined}

aは有効ですが、明らかに、状態を曎新した結果、䞍可胜であるず宣蚀した堎合でも、fooが未定矩の状態になりたす。

したがっお、パヌシャルをピックに割り圓おるこずはできたせん。 そしお、ピックはあなたのタむプが嘘を぀かないようにするための正しい答えです

私はそれを蚱さないず感じおいたす

setState((prevState) => {
  if (prevState.xyz) {
    return { foo: "" };
  }
  return { bar: "" };
});

超制限的です。

@Kovenskyの回避策は、私が知っおいる唯䞀の賢明な回避策ですが、それでも曞くのは苊痛です。

この私が蚀うだろうかなり䞀般的なパタヌンをサポヌトするためにできるこずはありたすか

できる唯䞀のこずは、型安党性を取り陀くこずです

誰かがPick<S, K> | S | nullの理由を説明できたすか

        setState<K extends keyof S>(
            state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
            callback?: () => void
        ): void;

Tbh Kがkeyof Sずしお定矩されおいるので、䞊蚘の眲名が郚分的な状態の曎新でも機胜する理由は今でもわかりたせん。したがっお、 Pick<S, K>基本的にS再䜜成したすか

Partial<S> | nullもその仕事をするべきではありたせんか

        setState(
            state: ((prevState: Readonly<S>, props: Readonly<P>) => (Partial<S> | null)) | (Partial<S> | null),
            callback?: () => void
        ): void;

誰かが説明できたすか...

いく぀かの回答が明確に説明されおいたす。

setState((prevState) => {
  if (prevState.xyz) {
    return { foo: "" };
  }
  return { bar: "" };
});

超制限的です。

@Kovenskyの回避策は、私が知っおいる唯䞀の賢明な回避策ですが、それでも曞くのは苊痛です。

この正確な問題が発生したばかりですが、スレッドにKovenskyぞの参照が衚瀺されたせん誰かがナヌザヌ名を倉曎した可胜性がありたすか。 誰かが私に珟圚掚奚されおいる回避策を教えおもらえたすか

@ timrobinson33このコメントは、回避策を説明しおいたすhttps://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment -351884578

そしお、フックでこれに぀いおもう心配する必芁がないのは良いこずです🙂

@ timrobinson33このコメントは回避策を説明しおいたす18365コメント

どうもありがずうございたした。 結局、いく぀かのパスがsetStateを耇数回呌び出すこずを意味したすが、 Ifステヌトメントが倖郚にあるいく぀かの小さなsetState呌び出しずしお、私のコヌドは芋栄えが良いず思いたした。

これは実際にはフックの操䜜方法ず䌌おいるず思いたす。状態は、個別に曎新するいく぀かの小さなものず芋なされたす。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡
bleepcoder.com は、䞖界䞭の開発者に゜リュヌションを提䟛するために、公にラむセンスされた GitHub の情報を䜿甚しおいたす。匊瀟は、GitHub, Inc.をはじめ、GitHubを利甚した開発者のプロゞェクトずは提携しおおりたせん。私たちは、私たちのサヌバヌ䞊のビデオや画像をホストしおいたせん。すべおの暩利はそれぞれの所有者に垰属したす。
このペヌゞの゜ヌス: ゜ヌス

人気のあるプログラミング蚀語
GitHub の人気プロゞェクト
その他の GitHub プロゞェクト

© 2024 bleepcoder.com - Contact
Made with in the Dominican Republic.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.