typescript - Hur specificerar jag rätt returtyp för mapStateToProps?


I min mapStateToProps nedan skulle jag vilja ange en explicit TypeScript-returtyp:

interface CounterProps {
    sequence: number;
    count: number;
}

class Counter extends Component<CounterProps> { 

    public static defaultProps = {
        sequence: 0,
        count: 0
    };

    public render() {
        const sequence = this.props.sequence
        const count = this.props.count

        return (
            // Some use of sequence, count ...
        )
    }
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const mapStateToProps = (state: CounterState) => ({
    count: state.count,
})
export default connect(mapStateToProps)(Counter)

Men den uppenbara lösningen att använda Partial med

const mapStateToProps = (state: CounterState): Partial<CounterProps> => ({
        count: state.count,
    })

misslyckas med TS2345 vid anropet av connect (Counter kan inte tilldelas den förväntade typen).

Alternativt, att göra den icke-returnerade medlemmen valfri med

interface CounterProps {
    sequence?: number;
    count: number;
}

tillåter

const mapStateToProps = (state: CounterState): CounterProps => ({
    count: state.count,
})

att fungera, men resulterar i TS2352 (möjligen odefinierad) för alla användningar av sequence i render.

Hur specificerar jag rätt returtyp för mapStateToProps, som enligt specifikationen endast behöver returnera en delmängd av medlemmarna i den motsvarande typen?

Svar #1

Prova Pick<T, K>-hjälpverktygstypen

Eftersom du bara returnerar ett objekt med en enda egenskap "count" från CounterProps, borde du kunna använda Pick<CounterProps, 'count'> som returtyp för mapStateToProps.

Pick är också användbart när man anropar setState med en callback när man ändrar tillståndet baserat på det befintliga tillståndet. Till exempel:

interface ComponentState {
  active: true;
  something: number;
  else: string;
}

class MyComponent extends React.Component<{}, ComponentState> {
  constructor(props) {
    super(props);

    this.state = { 
      active: false,
      something: 123,
      else: 'hello world',
    };
  }

  toggle(): void {
    this.setState((state: ComponentState): Pick<ComponentState, 'active'> ({
      active: !state.active,
    }));
  }

  render(): React.ReactElement {
    // ...
  }
}