react.dev icon indicating copy to clipboard operation
react.dev copied to clipboard

[Question - Beta docs] Is there TypeScript version of examples?

Open kevinadhiguna opened this issue 2 years ago • 3 comments
trafficstars

Hi, I was looking at basic useReducer examples in the beta version of React docs and am wondering if there's TypeScript version of them.

In my opinion, it would be a great addition if it doesn't exist yet. Thanks in advance!

kevinadhiguna avatar Feb 14 '23 12:02 kevinadhiguna

Not at the moment, but we'd like to make an effort to add that. Requires solving some technical challenges.

gaearon avatar Feb 14 '23 14:02 gaearon

@kevinadhiguna

I can try and provide an example! Maybe if a senior dev reads this they might have some corrections, however:

Typescript's main feature is it's static type system.

Basically, what STS means is that when we compile our code, variables must already have their types (boolean, string) defined.

When we analyze the JavaScript code in the example you asked about we see:

  1. A function including the hook; useReducer. This will affect age, by incrementing whatever number is received as input. name is changed according to user input:
function reducer(state, action) {
  switch (action.type) {
    case 'incremented_age': {
      return {
        name: state.name,
        age: state.age + 1
      };
    }
    case 'changed_name': {
      return {
        name: action.nextName,
        age: state.age
      };
    }
  }
  throw Error('Unknown action: ' + action.type);
}
  1. A React component that introduces 2 objects, name: Taylor and age: 42

const initialState = { name: 'Taylor', age: 42 };

  1. Callback functions, handleButtonClick and handleInputChange, which respond to the changes by useReducer to name and age by updating the screen. Likewise, including dispatch will allow for re-renders for states.
export default function Form() {
  const [state, dispatch] = useReducer(reducer, initialState);

  function handleButtonClick() {
    dispatch({ type: 'incremented_age' });
  }

  function handleInputChange(e) {
    dispatch({
      type: 'changed_name',
      nextName: e.target.value
    }); 
  }
  1. A return function:
  return (
    <>
      <input
        value={state.name}
        onChange={handleInputChange}
      />
      <button onClick={handleButtonClick}>
        Increment age
      </button>
      <p>Hello, {state.name}. You are {state.age}.</p>
    </>
  );
}

Converting the aforementioned to Typescript would look something like this:

import { useReducer } from 'react';

type State = { name: string, age: number };
type Action =
  | { type: 'incremented_age' }
  | { type: 'changed_name', nextName: string };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'incremented_age': {
      return {
        name: state.name,
        age: state.age + 1
      };
    }
    case 'changed_name': {
      return {
        name: action.nextName,
        age: state.age
      };
    }
    default: throw Error('Unknown action: ' + action.type);
  }
}

const initialState: State = { name: 'Taylor', age: 42 };

export default function Form() {
  const [state, dispatch] = useReducer(reducer, initialState);

  function handleButtonClick() {
    dispatch({ type: 'incremented_age' });
  }

  function handleInputChange(e: ChangeEvent<HTMLInputElement>) {
    dispatch({
      type: 'changed_name',
      nextName: e.target.value
    }); 
  }

  return (
    <>
      <input
        value={state.name}
        onChange={handleInputChange}
      />
      <button onClick={handleButtonClick}>
        Increment age
      </button>
      <p>Hello, {state.name}. You are {state.age}.</p>
    </>
  );
}

In any case, you might benefit from going example by example and working on re-writing each component with Typescript as an exercise. I might do the same!

kandoradev avatar Feb 14 '23 15:02 kandoradev

@kevinadhiguna I think this site will help you. React TypeScript Cheatsheet #usereducer

0ldh avatar Feb 16 '23 02:02 0ldh