3

I am having to convert a React app to Typescript and I can't figure out to property set the initial state of hash object.

original js

export default class Wizard extends PureComponent {
    constructor(props) {
        super(props);

        this.state = this.initialState();
    }



    /** Setup Steps */
    initialState = () => {
        const state = {
            activeStep: 0,
            hashKeys: {},
        };

        // Set initial classes
        // Get hash only in client side
        const hash = typeof window === 'object' ? this.getHash() : '';
        const children = React.Children.toArray(this.getSteps());
        children.forEach((child, i) => {
            // Create hashKey map
            state.hashKeys[i] = (child.props && child.props.hashKey) || `step${i + 1}`;
            state.hashKeys[state.hashKeys[i]] = i;
        });

        ...

        return state;
    }
...

My Failed Attempt

export interface TState {
  activeStep?: number
  hashKeys: {
    [key: number]: string
  }
}

export default class StepWizard extends PureComponent<{},TState> {
   constructor(props: IStepWizardProps) {
       super(props)
       this.state = this.initialState()
   }

   initialState = () => {
    const state = {
      activeStep: 0,
      hashKeys: {},  /* <---- This seems to be the problem */
    }

    // Set initial classes
    // Get hash only in client side
    const hash = typeof window === "object" ? this.getHash() : ""

    const children = React.Children.toArray(this.getSteps())
    children.forEach((child, i) => {
      // Create hashKey map
      // the following give a TS error
      // ERROR: (property) hashKeys: {}
      //           Element implicitly has an 'any' type because expression of type 'number' 
      //           can't be used to index type '{}'.
      //        No index signature with a parameter of type 'number' was found on type '{}'.ts(7053)
      state.hashKeys[i] = (child.props && child.props.hashKey) || `step${i + 1}`
      state.hashKeys[state.hashKeys[i]] = i
    })

   ...

I get for state.hasKeys[i] (property) hashKeys: {} Element implicitly has an 'any' type because expression of type 'number' can't be used to index type '{}'. No index signature with a parameter of type 'number' was found on type '{}'.ts(7053)

2 Answers 2

2

The problem seems to come from the definition of hashKeys as {}.

Typescript doesn't know what the types of data will be for the key/value, but, you can tell it!

const hashKeys = {} as Record<number, string>;

const x = hashKeys[0];

For your example:

        const state = {
            activeStep: 0,
            hashKeys: {} as Record<string, string>, // or whatever your types are
        };
Sign up to request clarification or add additional context in comments.

3 Comments

would const state: TState = { activeStep: 0, hashKeys: {} } work too?
Much appreciated. I am learning a lot from your TS answers :D
1

Option 1: Type Union

export interface TState {
  activeStep?: number;
  hashKeys: {
    [key: number]: string
  } | {};
}

This syntax indicates that hashKeys could take the shape of either {[key: number]: string} or {}.

If you wanted to improve the readability of that union, you could do this:

type HashMap = {
  [key: number]: string;
}

export interface TState {
  activeStep?: number;
  hashKeys: HashMap | {};
}


Option 2: Partial (pssst probably not optimal - see option 3)

Partial constructs a type with all properties set to optional, which means that {} fits the definition by having both non-existent key and value properties.

type HashMap = {
  [key: number]: string;
}

export interface TState {
  activeStep?: number;
  hashKeys: Partial<HashMap>
}


Option 3: Type assertion

As pointed out in this answer, this approach does a better job of striking "a balance between correctness and productivity."

type HashMap = {
  [key: number]: string;
}

export interface TState {
  activeStep?: number;
  hashKeys: HashMap;
}

//

const state = {
  activeStep: 0,
  hashKeys: {} as HashMap,
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.