简体   繁体   中英

Assign types on setState to React Typescript

I'm working on the project that uses TypeScript and React and I'm trying to restrict the data based on interface assigned to state.

I have assigned the type IState interface to the state which has uiForm key assigns with type studentForm interface . But when I am assigning the wrong structured data or with wrong key which is not present in the studentForm Interface to uiForm key, it gets assigned without validating the type.

My code looks like this:

interface IProps {}

interface studentForm {
    label: string,
    type: string,
    sequen: string
}

interface IState {
    uiForm: Array < studentForm >
}

export default class AddStudent extends React.Component < IProps, IState > {
    state: IState = {
        uiForm: []
    }
    constructor(props: IProps) {
        super(props);
    }
    componentDidMount() {
        fetch('./assets/studentForm.json').then((res) => res.json())
            .then((data) => {
                this.setState({
                    uiForm: data
                })
            })
            .catch(err => {
                console.log(err);
            })
    }
}

I am trying to assign the uiForm with below object

studentForm.json:

{ 
   "label":"Admission No.",
   "type":"text",
   "sequence":1
}

Ideally, it should not be assigned but it is assigning

What would be the proper way to assign the types to state/setState? Thank you.

setState is not the crux here - if you look at the type signature of fetch , you see that it returns a Response object with Body interface like this:

interface Body {
  ...
  json(): Promise<any>;
}

So data effectively becomes any typed and any can be assigned to... anything..., which makes this.setState({ uiForm: data }) properly typed.

If you need to validate the fetch result first, annotate data with type unknown and then do a run-time check with type guards (branching logic) or assertion functions (assert/invariant logic; TS 3.7). An assertion example:

export default class AddStudent extends React.Component<IProps, IState> {
    ...
    componentDidMount() {
        fetch('./assets/studentForm.json').then((res) => res.json())
            // type data as unknown
            .then((data: unknown) => {
                // assertion function narrows data type or throws error
                assertStudentFormArray(data)
                // data type narrowed to Array<studentForm> here
                this.setState({
                    uiForm: data
                })
            })
    }
}

function assertStudentFormArray(args: any): asserts args is IState["uiForm"] {
    // do your validation here ...
    if (!Array.isArray(args)) throw new Error("Got no array...")
    if (args.some(arg => !("label" in arg))) throw new Error("Got no studentform...")
}

Playground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM