Gathering detailed insights and metrics for @sanity-typed/groq-js
Gathering detailed insights and metrics for @sanity-typed/groq-js
Gathering detailed insights and metrics for @sanity-typed/groq-js
Gathering detailed insights and metrics for @sanity-typed/groq-js
Completing sanity's developer experience with typescript (and more)!
npm install @sanity-typed/groq-js
Typescript
Module System
Node Version
NPM Version
@sanity-typed/next-sanity@4.0.2
Updated on May 27, 2025
@sanity-typed/groq@3.0.2
Updated on May 27, 2025
@sanity-typed/faker@4.0.2
Updated on May 27, 2025
@sanity-typed/client-mock@4.0.2
Updated on May 27, 2025
@sanity-typed/client@5.0.2
Updated on May 27, 2025
@sanity-typed/groq-js@3.0.2
Updated on May 27, 2025
TypeScript (99.94%)
JavaScript (0.06%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
158 Stars
1,706 Commits
8 Forks
3 Watchers
5 Branches
5 Contributors
Updated on Jul 10, 2025
Latest Version
3.0.2
Package Id
@sanity-typed/groq-js@3.0.2
Unpacked Size
17.46 kB
Size
6.26 kB
File Count
5
NPM Version
10.8.2
Node Version
20.19.1
Published on
May 27, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
2
2
groq-js with typed GROQ Results
1npm install groq-js @sanity-typed/groq-js
Use parse
and evaluate
exactly as you would from groq-js
. Then, use the results with the typescript types!
Typically, this isn't used directly, but via @sanity-typed/client-mock
's methods that produce groq results. But it can be done directly:
your-typed-groq-js.ts
:
1// import { evaluate, parse } from "groq-js"; 2import { evaluate, parse } from "@sanity-typed/groq-js"; 3 4const input = '*[_type == "product"]{productName}'; 5 6const tree = parse(input); 7/** 8 * typeof tree === { 9 * type: "Projection"; 10 * base: { 11 * type: "Filter"; 12 * base: { 13 * type: "Everything"; 14 * }; 15 * expr: { 16 * type: "OpCall"; 17 * op: "=="; 18 * left: { 19 * name: "_type"; 20 * type: "AccessAttribute"; 21 * }; 22 * right: { 23 * type: "Value"; 24 * value: "product"; 25 * }; 26 * }; 27 * }; 28 * expr: { 29 * type: "Object"; 30 * attributes: [{ 31 * type: "ObjectAttributeValue"; 32 * name: "productName"; 33 * value: { 34 * type: "AccessAttribute"; 35 * name: "productName"; 36 * }; 37 * }]; 38 * }; 39 * } 40 */ 41 42const value = await evaluate(tree, { 43 dataset: [ 44 { 45 _type: "product", 46 productName: "Some Cool Product", 47 // ... 48 }, 49 { 50 _type: "someOtherType", 51 otherField: "foo", 52 // ... 53 }, 54 ], 55}); 56 57const result = await value.get(); 58/** 59 * typeof result === [{ 60 * productName: "Some Cool Product"; 61 * }] 62 */
The supported Typescript version is now 5.7.2 <= x <= 5.7.3. Older versions are no longer supported and newer versions will be added as we validate them.
The supported Typescript version is now 5.4.2 <= x <= 5.6.3. Older versions are no longer supported and newer versions will be added as we validate them.
You can also use your typed schema to keep parity with the types your typed client would receive.
1npm install sanity groq-js @sanity-typed/types @sanity-typed/groq-js
product.ts
:
1// import { defineArrayMember, defineField, defineType } from "sanity"; 2import { 3 defineArrayMember, 4 defineField, 5 defineType, 6} from "@sanity-typed/types"; 7 8/** No changes using defineType, defineField, and defineArrayMember */ 9export const product = defineType({ 10 name: "product", 11 type: "document", 12 title: "Product", 13 fields: [ 14 defineField({ 15 name: "productName", 16 type: "string", 17 title: "Product name", 18 validation: (Rule) => Rule.required(), 19 }), 20 defineField({ 21 name: "tags", 22 type: "array", 23 title: "Tags for item", 24 of: [ 25 defineArrayMember({ 26 type: "object", 27 name: "tag", 28 fields: [ 29 defineField({ type: "string", name: "label" }), 30 defineField({ type: "string", name: "value" }), 31 ], 32 }), 33 ], 34 }), 35 ], 36});
sanity.config.ts
:
1import { structureTool } from "sanity/structure"; 2 3// import { defineConfig } from "sanity"; 4import { defineConfig } from "@sanity-typed/types"; 5import type { InferSchemaValues } from "@sanity-typed/types"; 6 7import { post } from "./schemas/post"; 8import { product } from "./schemas/product"; 9 10/** No changes using defineConfig */ 11const config = defineConfig({ 12 projectId: "59t1ed5o", 13 dataset: "production", 14 plugins: [structureTool()], 15 schema: { 16 types: [ 17 product, 18 // ... 19 post, 20 ], 21 }, 22}); 23 24export default config; 25 26/** Typescript type of all types! */ 27export type SanityValues = InferSchemaValues<typeof config>; 28/** 29 * SanityValues === { 30 * product: { 31 * _createdAt: string; 32 * _id: string; 33 * _rev: string; 34 * _type: "product"; 35 * _updatedAt: string; 36 * productName: string; 37 * tags?: { 38 * _key: string; 39 * _type: "tag"; 40 * label?: string; 41 * value?: string; 42 * }[]; 43 * }; 44 * // ... all your types! 45 * } 46 */
your-typed-groq-js-with-sanity-types.ts
:
1// import { evaluate, parse } from "groq-js"; 2import { evaluate, parse } from "@sanity-typed/groq-js"; 3import type { DocumentValues } from "@sanity-typed/types"; 4 5import type { SanityValues } from "./sanity.config"; 6 7const input = '*[_type == "product"]{productName}'; 8 9const tree = parse(input); 10 11const value = await evaluate(tree, { 12 dataset: [ 13 { 14 _type: "product", 15 productName: "Some Cool Product", 16 // ... 17 }, 18 { 19 _type: "someOtherType", 20 otherField: "foo", 21 // ... 22 }, 23 ] satisfies DocumentValues<SanityValues>[], 24}); 25 26const result = await value.get(); 27/** 28 * typeof result === { 29 * productName: string; 30 * }[] 31 */ 32 33// Notice how `productName` is inferred as a `string`, not as `"Some Cool Product"`. 34// Also, it's in an array as opposed to a tuple. 35// This resembles the types you'd receive from @sanity-typed/client, 36// which wouldn't be statically aware of `"Some Cool Product"` either.
@sanity-typed/groq
attempts to type its parsed types as close as possible to groq-js
's parse
function output. Any fixes to match it more correctly won't be considered a major change and, if groq-js
changes it's output in a version update, we're likely to match it. If you're using the parsed tree's types directly, this might cause your code to break. We don't consider this a breaking change because the intent of these groq libraries is to match the types of a groq query as closely as possible.
Similar to parsing, evaluating groq queries will attempt to match how sanity actually evaluates queries. Again, any fixes to match that or changes to groq evaluation will likely not be considered a major change but, rather, a bug fix.
Often you'll run into an issue where you get typescript errors in your IDE but, when building workspace (either you studio or app using types), there are no errors. This only occurs because your IDE is using a different version of typescript than the one in your workspace. A few debugging steps:
JavaScript and TypeScript Nightly
extension (identifier ms-vscode.vscode-typescript-next
) creates issues here by design. It will always attempt to use the newest version of typescript instead of your workspace's version. I ended up uninstalling it..vscode/settings.json
. Use TypeScript: Select TypeScript Version
to explictly pick the workspace version.Type instantiation is excessively deep and possibly infinite
🚨 CHECK Typescript Errors in IDEs
FIRST!!! ISSUES WILL GET CLOSED IMMEDIATELY!!! 🚨
You might run into the dreaded Type instantiation is excessively deep and possibly infinite
error when writing GROQ queries. This isn't too uncommon with more complex GROQ queries. Unfortunately, this isn't a completely avoidable problem, as typescript has limits on complexity and parsing types from a string is an inherently complex problem. A set of steps for a workaround:
@ts-expect-error
to disable the error. You could use @ts-ignore
instead, but ideally you'd like to remove the comment if a fix is released.groq/src/specific-issues.test.ts
with your issue. #642 is a great example for this. Try to reduce your query and config as much as possible. The goal is a minimal reproduction.People will sometimes create a repo with their issue. Please open a PR with a minimal test instead. Without a PR there will be no tests reflecting your issue and it may appear again in a regression. Forking a github repo to make a PR is a more welcome way to contribute to an open source library.
No vulnerabilities found.
No security vulnerabilities found.