Skip to content

Commit

Permalink
Improve useValue type inference (#1617)
Browse files Browse the repository at this point in the history
  • Loading branch information
ovidiuch committed Feb 15, 2024
1 parent 2314a55 commit 2806ea7
Show file tree
Hide file tree
Showing 14 changed files with 33 additions and 55 deletions.
2 changes: 1 addition & 1 deletion examples/todo/src/components/TodoContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type ProviderProps = {
children: React.ReactNode;
};
export function TodoProvider({ children }: ProviderProps) {
const [todos, setTodos] = useValue<Todo[]>('todos', {
const [todos, setTodos] = useValue('todos', {
defaultValue: React.useMemo(
() => [
{
Expand Down
4 changes: 2 additions & 2 deletions examples/todo/src/components/TodoList/TodoItem.fixture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { useValue } from 'react-cosmos/client';
import { TodoItem } from './TodoItem.js';

export default () => {
const [label, setLabel] = useValue<string>('label', {
const [label, setLabel] = useValue('label', {
defaultValue: 'Eat the homework',
});

const [done, setDone] = useValue<boolean>('done', {
const [done, setDone] = useValue('done', {
defaultValue: false,
});

Expand Down
2 changes: 1 addition & 1 deletion examples/vite/src/CounterButton.fixture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import { useValue } from 'react-cosmos/client';

export default () => {
const [count, setCount] = useValue<number>('count', { defaultValue: 0 });
const [count, setCount] = useValue('count', { defaultValue: 0 });
return (
<CounterButton
suffix="times"
Expand Down
2 changes: 1 addition & 1 deletion examples/webpack/src/CounterButton.fixture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import { useValue } from 'react-cosmos/client';

export default () => {
const [count, setCount] = useValue<number>('count', { defaultValue: 0 });
const [count, setCount] = useValue('count', { defaultValue: 0 });
return (
<CounterButton
suffix="times"
Expand Down
2 changes: 0 additions & 2 deletions packages/react-cosmos-core/src/fixtureState/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export type ObjectData = Record<string, unknown>;

export type ArrayData = unknown[];

export type FixtureStateData = PrimitiveData | ObjectData | ArrayData;

export type FixtureStatePrimitiveValue = {
type: 'primitive';
data: PrimitiveData;
Expand Down
8 changes: 3 additions & 5 deletions packages/react-cosmos-renderer/src/fixture/useValue/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { FixtureStateData } from 'react-cosmos-core';
import { SetValue } from './shared.js';
import { useCreateFixtureState } from './useCreateFixtureState.js';
import { useCurrentValue } from './useCurrentValue.js';
import { useSetValue } from './useSetValue.js';

type Opts<T extends FixtureStateData> = {
type Opts<T> = {
defaultValue: T;
};

export function useValue<T extends FixtureStateData>(
export function useValue<T>(
inputName: string,
{ defaultValue }: Opts<T>
): [T, SetValue<T>] {
): [T, React.Dispatch<React.SetStateAction<T>>] {
useCreateFixtureState(inputName, defaultValue);
const currentValue = useCurrentValue(inputName, defaultValue);
const setValue = useSetValue(inputName, defaultValue);
Expand Down
6 changes: 0 additions & 6 deletions packages/react-cosmos-renderer/src/fixture/useValue/shared.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { isEqual } from 'lodash-es';
import React from 'react';
import {
ControlsFixtureState,
FixtureStateData,
FixtureStateValue,
createValue,
extendWithValue,
Expand All @@ -11,7 +10,7 @@ import { useFixtureState } from '../useFixtureState.js';

export function useCreateFixtureState(
inputName: string,
defaultValue: FixtureStateData
defaultValue: unknown
) {
const [, setFixtureState] = useFixtureState<ControlsFixtureState>('controls');
React.useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import {
ControlsFixtureState,
FixtureStateData,
extendWithValue,
} from 'react-cosmos-core';
import { ControlsFixtureState, extendWithValue } from 'react-cosmos-core';
import { useFixtureState } from '../useFixtureState.js';

export function useCurrentValue<T extends FixtureStateData>(
inputName: string,
defaultValue: T
): T {
export function useCurrentValue<T>(inputName: string, defaultValue: T): T {
const [fixtureState] = useFixtureState<ControlsFixtureState>('controls');
const controlFs = fixtureState && fixtureState[inputName];
return controlFs && controlFs.type === 'standard'
? // Types of fixture state values cannot be guaranteed at read time, which
? // Types of fixture state values cannot be guaranteed at run time, which
// means that tampering with the fixture state can cause runtime errors
(extendWithValue(defaultValue, controlFs.currentValue) as T)
: defaultValue;
Expand Down
34 changes: 15 additions & 19 deletions packages/react-cosmos-renderer/src/fixture/useValue/useSetValue.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import React from 'react';
import {
ControlsFixtureState,
FixtureStateData,
createValue,
extendWithValue,
} from 'react-cosmos-core';
import { useFixtureState } from '../useFixtureState.js';
import { SetValue } from './shared.js';

export function useSetValue<T extends FixtureStateData>(
export function useSetValue<T>(
inputName: string,
defaultValue: T
): SetValue<T> {
): React.Dispatch<React.SetStateAction<T>> {
const [, setFixtureState] = useFixtureState<ControlsFixtureState>('controls');
return React.useCallback(
stateChange => {
setFixtureState(prevFs => {
const currentValue: FixtureStateData =
typeof stateChange === 'function'
? stateChange(
// Types of fixture state values cannot be guaranteed at read
// time, which means that tampering with the fixture state can
// cause runtime errors
getCurrentValueFromFixtureState(
prevFs,
inputName,
defaultValue
) as T
)
: stateChange;
// Types of fixture state values cannot be guaranteed at run
// time, which means that tampering with the fixture state can
// cause runtime errors
function getNewState() {
if (typeof stateChange !== 'function') return stateChange;

const stateUpdater = stateChange as (prevState: unknown) => unknown;
return stateUpdater(
getCurrentValueFromFixtureState(prevFs, inputName, defaultValue)
);
}

return {
...prevFs,
[inputName]: {
type: 'standard',
defaultValue: createValue(defaultValue),
currentValue: createValue(currentValue),
currentValue: createValue(getNewState()),
},
};
});
Expand All @@ -47,7 +43,7 @@ export function useSetValue<T extends FixtureStateData>(
function getCurrentValueFromFixtureState(
fixtureState: ControlsFixtureState | undefined,
inputName: string,
defaultValue: FixtureStateData
defaultValue: unknown
) {
const controlFs = fixtureState && fixtureState[inputName];
return controlFs && controlFs.type === 'standard'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ const Container = styled.div`
`;

export default () => {
const [nr1, setNr1] = useValue<number>('number1', { defaultValue: 0.93 });
const [nr2, setNr2] = useValue<number>('number2', { defaultValue: 1337 });
const [nr3, setNr3] = useValue<number>('number3', { defaultValue: 0 });
const [nr1, setNr1] = useValue('number1', { defaultValue: 0.93 });
const [nr2, setNr2] = useValue('number2', { defaultValue: 1337 });
const [nr3, setNr3] = useValue('number3', { defaultValue: 0 });
return (
<Container>
<NumberInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default {

function createFixture(fixtureId: null | FixtureId = null) {
return () => {
const [searchText, setSearchText] = useValue<string>('searchText', {
const [searchText, setSearchText] = useValue('searchText', {
defaultValue: '',
});
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default () => {
const [viewport, setViewport] = useValue('viewport', {
defaultValue: initialViewport,
});
const [scaled, setScaled] = useValue<boolean>('scaled', {
const [scaled, setScaled] = useValue('scaled', {
defaultValue: false,
});
const scaleFactor = getViewportScaleFactor(viewport, containerViewport);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default () => {
const [viewport, setViewport] = useValue('viewport', {
defaultValue: initialViewport,
});
const [scaled, setScaled] = useValue<boolean>('scaled', {
const [scaled, setScaled] = useValue('scaled', {
defaultValue: false,
});
return (
Expand Down

0 comments on commit 2806ea7

Please sign in to comment.