S
SolidJS3mo ago
Eve

How to type the context from the docs example

Using the example from here I'm trying to get it working in TS, but TS doesn't seem to understand <CounterContext.Provider and throws all kinds of errors. Does anyone know how to make this work?
import { createContext, createSignal, useContext } from "solid-js";
import type { ParentProps } from "solid-js";

const CounterContext = createContext<number>(0);

export function CounterProvider(props: ParentProps & { initialCount?: number }) {
const [count, setCount] = createSignal(props.initialCount || 0);
const counter = [
count,
{
increment() {
setCount(prev => prev + 1);
},
decrement() {
setCount(prev => prev - 1);
}
}
];

return (
<CounterContext.Provider value={counter}>
{props.children}
</CounterContext.Provider>
);
}

export function useCounter() { return useContext(CounterContext); }
import { createContext, createSignal, useContext } from "solid-js";
import type { ParentProps } from "solid-js";

const CounterContext = createContext<number>(0);

export function CounterProvider(props: ParentProps & { initialCount?: number }) {
const [count, setCount] = createSignal(props.initialCount || 0);
const counter = [
count,
{
increment() {
setCount(prev => prev + 1);
},
decrement() {
setCount(prev => prev - 1);
}
}
];

return (
<CounterContext.Provider value={counter}>
{props.children}
</CounterContext.Provider>
);
}

export function useCounter() { return useContext(CounterContext); }
13 Replies
Eve
EveOP3mo ago
The TS errors, if that helps
[{
"resource": "test.ts",
"owner": "typescript",
"code": "2503",
"severity": 8,
"message": "Cannot find namespace 'CounterContext'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 6,
"endLineNumber": 21,
"endColumn": 20
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1005",
"severity": 8,
"message": "'>' expected.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 30,
"endLineNumber": 21,
"endColumn": 35
},{
"resource": "test.ts",
"owner": "typescript",
"code": "2304",
"severity": 8,
"message": "Cannot find name 'value'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 30,
"endLineNumber": 21,
"endColumn": 35
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1005",
"severity": 8,
"message": "')' expected.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 35,
"endLineNumber": 21,
"endColumn": 36
},{
"resource": "test.ts",
"owner": "typescript",
"code": "2365",
"severity": 8,
"message": "Operator '>' cannot be applied to types '{ counter: (Accessor<number> | { increment(): void; decrement(): void; })[]; }' and '{ props: { children?: JSX.Element; } & { initialCount?: number; }; \"\": any; }'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 36,
"endLineNumber": 22,
"endColumn": 23
},{
"resource": "test.ts",
"owner": "typescript",
"code": "2365",
"severity": 8,
"message": "Operator '<' cannot be applied to types 'boolean' and 'RegExp'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 36,
"endLineNumber": 23,
"endColumn": 31
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1005",
"severity": 8,
"message": "',' expected.",
"source": "ts",
"startLineNumber": 22,
"startColumn": 13,
"endLineNumber": 22,
"endColumn": 14
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1161",
"severity": 8,
"message": "Unterminated regular expression literal.",
"source": "ts",
"startLineNumber": 23,
"startColumn": 6,
"endLineNumber": 23,
"endColumn": 31
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1128",
"severity": 8,
"message": "Declaration or statement expected.",
"source": "ts",
"startLineNumber": 24,
"startColumn": 3,
"endLineNumber": 24,
"endColumn": 4
}]
[{
"resource": "test.ts",
"owner": "typescript",
"code": "2503",
"severity": 8,
"message": "Cannot find namespace 'CounterContext'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 6,
"endLineNumber": 21,
"endColumn": 20
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1005",
"severity": 8,
"message": "'>' expected.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 30,
"endLineNumber": 21,
"endColumn": 35
},{
"resource": "test.ts",
"owner": "typescript",
"code": "2304",
"severity": 8,
"message": "Cannot find name 'value'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 30,
"endLineNumber": 21,
"endColumn": 35
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1005",
"severity": 8,
"message": "')' expected.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 35,
"endLineNumber": 21,
"endColumn": 36
},{
"resource": "test.ts",
"owner": "typescript",
"code": "2365",
"severity": 8,
"message": "Operator '>' cannot be applied to types '{ counter: (Accessor<number> | { increment(): void; decrement(): void; })[]; }' and '{ props: { children?: JSX.Element; } & { initialCount?: number; }; \"\": any; }'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 36,
"endLineNumber": 22,
"endColumn": 23
},{
"resource": "test.ts",
"owner": "typescript",
"code": "2365",
"severity": 8,
"message": "Operator '<' cannot be applied to types 'boolean' and 'RegExp'.",
"source": "ts",
"startLineNumber": 21,
"startColumn": 36,
"endLineNumber": 23,
"endColumn": 31
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1005",
"severity": 8,
"message": "',' expected.",
"source": "ts",
"startLineNumber": 22,
"startColumn": 13,
"endLineNumber": 22,
"endColumn": 14
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1161",
"severity": 8,
"message": "Unterminated regular expression literal.",
"source": "ts",
"startLineNumber": 23,
"startColumn": 6,
"endLineNumber": 23,
"endColumn": 31
},{
"resource": "test.ts",
"owner": "typescript",
"code": "1128",
"severity": 8,
"message": "Declaration or statement expected.",
"source": "ts",
"startLineNumber": 24,
"startColumn": 3,
"endLineNumber": 24,
"endColumn": 4
}]
REEEEE
REEEEE3mo ago
Change the file extension from ts to tsx
Eve
EveOP3mo ago
:facepalm:
thesamsterau
thesamsterau2mo ago
Hello, I hope you don't mind me piggy-backing on this discussion. I am trying to use Context in TypeScript but I can't seem to figure out how to keep the compiler happy. Here is my attempt:
import { render } from "solid-js/web";
import {
createSignal,
createMemo,
createContext,
useContext,
ParentProps,
} from "solid-js";

const CounterContext = createContext();

export function CounterProvider(props: ParentProps) {
const [count, setCount] = createSignal(0);
const counter = [
count,
{
increment() {
setCount((prev) => prev + 1);
},
decrement() {
setCount((prev) => prev - 1);
},
},
];
return (
<CounterContext.Provider value={counter}>
{props.children}
</CounterContext.Provider>
);
}

function useCounterContext() {
const context = useContext(CounterContext);
if (!context) {
throw new Error("can't find CounterContext");
}
return context;
}

function Counter() {
const {counter: [count, { increment, decrement }]
} = useCounterContext(); // Error: Property 'counter' does not exist on type '{}'.

...
return (
<>
...
</>
);
}

render(
() => (
<CounterProvider>
<Counter />
</CounterProvider>
),
document.getElementById("app")!,
);
import { render } from "solid-js/web";
import {
createSignal,
createMemo,
createContext,
useContext,
ParentProps,
} from "solid-js";

const CounterContext = createContext();

export function CounterProvider(props: ParentProps) {
const [count, setCount] = createSignal(0);
const counter = [
count,
{
increment() {
setCount((prev) => prev + 1);
},
decrement() {
setCount((prev) => prev - 1);
},
},
];
return (
<CounterContext.Provider value={counter}>
{props.children}
</CounterContext.Provider>
);
}

function useCounterContext() {
const context = useContext(CounterContext);
if (!context) {
throw new Error("can't find CounterContext");
}
return context;
}

function Counter() {
const {counter: [count, { increment, decrement }]
} = useCounterContext(); // Error: Property 'counter' does not exist on type '{}'.

...
return (
<>
...
</>
);
}

render(
() => (
<CounterProvider>
<Counter />
</CounterProvider>
),
document.getElementById("app")!,
);
What am I doing wrong?
REEEEE
REEEEE2mo ago
You didn't specify the type for the context on createContext. You have to do this:
type MyContextType = [Accessor<number>, {increment: () => void, decrement: () => void}]
const CounterContext = createContext<MyContextType>();
type MyContextType = [Accessor<number>, {increment: () => void, decrement: () => void}]
const CounterContext = createContext<MyContextType>();
thesamsterau
thesamsterau2mo ago
return (
<CounterContext.Provider value={counter}>
{props.children}
</CounterContext.Provider>
);
return (
<CounterContext.Provider value={counter}>
{props.children}
</CounterContext.Provider>
);
value is erroring with:
Type '(Accessor<number> | { increment(): void; decrement(): void; })[]' is not assignable to type '[Accessor<number>, { increment: () => void; decrement: () => void; }]'.
Target requires 2 element(s) but source may have fewer.(2322)
signal.d.ts(493, 5): The expected type comes from property 'value' which is declared here on type 'IntrinsicAttributes & { value: CounterContextProps | undefined; } & { children: Element; }'
Type '(Accessor<number> | { increment(): void; decrement(): void; })[]' is not assignable to type '[Accessor<number>, { increment: () => void; decrement: () => void; }]'.
Target requires 2 element(s) but source may have fewer.(2322)
signal.d.ts(493, 5): The expected type comes from property 'value' which is declared here on type 'IntrinsicAttributes & { value: CounterContextProps | undefined; } & { children: Element; }'
thesamsterau
thesamsterau2mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
REEEEE
REEEEE2mo ago
add satisfies CounterContextProps to the counter definition
REEEEE
REEEEE2mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
thesamsterau
thesamsterau2mo ago
While that takes care of the error in value, there's another error when I try to use the context. Please take a look at your playground. I want to use Context in a typesafe way, but it feels like I am missing some knowledge.
REEEEE
REEEEE2mo ago
Oh sorry I missed that It's an array but you're trying to destructure as an object
REEEEE
REEEEE2mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
thesamsterau
thesamsterau2mo ago
Thank you, I am beginning to understand how the typing works. I have a question: can I use SolidJS stores inside a context? I have tried but cannot seem to get past the TypeScript errors. Here is my attempt: https://playground.solidjs.com/anonymous/0375fc53-4580-46fa-b409-546982454524
Uncaught TypeError: Cannot read properties of undefined (reading 'randomize')
Uncaught TypeError: Cannot read properties of undefined (reading 'randomize')
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template

Did you find this page helpful?