From 9720b568cd302c597fd0030e59eceab2bb833e39 Mon Sep 17 00:00:00 2001 From: David Blass Date: Mon, 15 Apr 2024 15:14:17 -0400 Subject: [PATCH] refactor(store,world): refactor types, remove redundant casts (#2555) --- .changeset/late-bats-smash.md | 6 ++++ packages/store/package.json | 2 +- packages/store/ts/config/defaults.ts | 10 ++++-- packages/store/ts/config/v2/codegen.ts | 4 +-- packages/store/ts/config/v2/compat.ts | 2 +- packages/store/ts/config/v2/defaults.ts | 10 ++++++ packages/store/ts/config/v2/enums.ts | 4 +-- packages/store/ts/config/v2/generics.ts | 20 ++++++++--- packages/store/ts/config/v2/input.ts | 3 +- packages/store/ts/config/v2/output.ts | 11 +++--- packages/store/ts/config/v2/schema.ts | 12 +++---- packages/store/ts/config/v2/scope.ts | 2 +- packages/store/ts/config/v2/store.ts | 28 +++++++-------- .../store/ts/config/v2/storeWithShorthands.ts | 4 +-- packages/store/ts/config/v2/table.ts | 34 +++++++++---------- .../store/ts/config/v2/tableShorthand.test.ts | 6 ++-- packages/store/ts/config/v2/tableShorthand.ts | 18 +++++----- packages/store/ts/config/v2/tables.ts | 2 +- packages/store/ts/config/v2/userTypes.ts | 5 +-- packages/store/ts/register/typeExtensions.ts | 17 +++------- packages/world/package.json | 2 +- packages/world/ts/config/defaults.ts | 4 +++ packages/world/ts/config/types.ts | 6 ++-- packages/world/ts/config/v2/codegen.ts | 8 ++--- packages/world/ts/config/v2/compat.ts | 4 +-- packages/world/ts/config/v2/defaults.ts | 8 +++++ packages/world/ts/config/v2/deploy.ts | 6 ++-- packages/world/ts/config/v2/namespaces.ts | 15 ++++---- packages/world/ts/config/v2/world.ts | 6 ++-- .../world/ts/config/v2/worldWithShorthands.ts | 14 ++++---- packages/world/ts/register/typeExtensions.ts | 16 +-------- pnpm-lock.yaml | 12 +++---- 32 files changed, 158 insertions(+), 143 deletions(-) create mode 100644 .changeset/late-bats-smash.md diff --git a/.changeset/late-bats-smash.md b/.changeset/late-bats-smash.md new file mode 100644 index 0000000000..e8c1011901 --- /dev/null +++ b/.changeset/late-bats-smash.md @@ -0,0 +1,6 @@ +--- +"@latticexyz/store": patch +"@latticexyz/world": patch +--- + +Internal type improvements. diff --git a/packages/store/package.json b/packages/store/package.json index 6b6e777cee..7415b8a5b9 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -59,7 +59,7 @@ "test:ci": "pnpm run test" }, "dependencies": { - "@arktype/util": "0.0.27", + "@arktype/util": "0.0.29", "@latticexyz/common": "workspace:*", "@latticexyz/config": "workspace:*", "@latticexyz/protocol-parser": "workspace:*", diff --git a/packages/store/ts/config/defaults.ts b/packages/store/ts/config/defaults.ts index 328d4ffb8c..13207f351c 100644 --- a/packages/store/ts/config/defaults.ts +++ b/packages/store/ts/config/defaults.ts @@ -5,12 +5,16 @@ export const PATH_DEFAULTS = { codegenIndexFilename: "index.sol", } as const; +export type PATH_DEFAULTS = typeof PATH_DEFAULTS; + export const DEFAULTS = { namespace: "", - enums: {} as Record, - userTypes: {} as Record, + enums: {}, + userTypes: {}, } as const; +export type DEFAULTS = typeof DEFAULTS; + export const TABLE_DEFAULTS = { directory: "tables", keySchema: { key: "bytes32" }, @@ -18,3 +22,5 @@ export const TABLE_DEFAULTS = { storeArgument: false, offchainOnly: false, } as const; + +export type TABLE_DEFAULTS = typeof TABLE_DEFAULTS; diff --git a/packages/store/ts/config/v2/codegen.ts b/packages/store/ts/config/v2/codegen.ts index 9d783ae435..b06076449d 100644 --- a/packages/store/ts/config/v2/codegen.ts +++ b/packages/store/ts/config/v2/codegen.ts @@ -2,8 +2,8 @@ import { CODEGEN_DEFAULTS } from "./defaults"; import { isObject, mergeIfUndefined } from "./generics"; export type resolveCodegen = codegen extends {} - ? mergeIfUndefined - : typeof CODEGEN_DEFAULTS; + ? mergeIfUndefined + : CODEGEN_DEFAULTS; export function resolveCodegen(codegen: codegen): resolveCodegen { return ( diff --git a/packages/store/ts/config/v2/compat.ts b/packages/store/ts/config/v2/compat.ts index 45aba9bd5a..185e0a0744 100644 --- a/packages/store/ts/config/v2/compat.ts +++ b/packages/store/ts/config/v2/compat.ts @@ -71,5 +71,5 @@ export function storeToV1(store: conform): storeToV1 codegenIndexFilename: store.codegen.indexFilename, tables: resolvedTables, v2: store, - } as unknown as storeToV1; + } as never; } diff --git a/packages/store/ts/config/v2/defaults.ts b/packages/store/ts/config/v2/defaults.ts index 5da3c10ffe..a5499144fd 100644 --- a/packages/store/ts/config/v2/defaults.ts +++ b/packages/store/ts/config/v2/defaults.ts @@ -5,21 +5,31 @@ export const CODEGEN_DEFAULTS = { indexFilename: "index.sol", } as const; +export type CODEGEN_DEFAULTS = typeof CODEGEN_DEFAULTS; + export const TABLE_CODEGEN_DEFAULTS = { outputDirectory: "tables", tableIdArgument: false, storeArgument: false, } as const; +export type TABLE_CODEGEN_DEFAULTS = typeof TABLE_CODEGEN_DEFAULTS; + export const TABLE_DEPLOY_DEFAULTS = { disabled: false, } as const; +export type TABLE_DEPLOY_DEFAULTS = typeof TABLE_DEPLOY_DEFAULTS; + export const TABLE_DEFAULTS = { namespace: "", type: "table", } as const; +export type TABLE_DEFAULTS = typeof TABLE_DEFAULTS; + export const CONFIG_DEFAULTS = { namespace: "", } as const; + +export type CONFIG_DEFAULTS = typeof CONFIG_DEFAULTS; diff --git a/packages/store/ts/config/v2/enums.ts b/packages/store/ts/config/v2/enums.ts index ae75886324..69096ef817 100644 --- a/packages/store/ts/config/v2/enums.ts +++ b/packages/store/ts/config/v2/enums.ts @@ -21,9 +21,9 @@ export function scopeWithEnums ): scopeWithEnums { if (isEnums(enums)) { const enumScope = Object.fromEntries(Object.keys(enums).map((key) => [key, "uint8" as const])); - return extendScope(scope, enumScope) as scopeWithEnums; + return extendScope(scope, enumScope) as never; } - return scope as scopeWithEnums; + return scope as never; } export type resolveEnums = { readonly [key in keyof enums]: Readonly }; diff --git a/packages/store/ts/config/v2/generics.ts b/packages/store/ts/config/v2/generics.ts index 312525506d..a269784c59 100644 --- a/packages/store/ts/config/v2/generics.ts +++ b/packages/store/ts/config/v2/generics.ts @@ -3,10 +3,20 @@ import { merge } from "@arktype/util"; export type get = key extends keyof input ? input[key] : undefined; export function get(input: input, key: key): get { - return (typeof input === "object" && input != null && hasOwnKey(input, key) ? input[key] : undefined) as get< - input, - key - >; + return (typeof input === "object" && input != null && hasOwnKey(input, key) ? input[key] : undefined) as never; +} + +export type getPath = path extends readonly [ + infer head, + ...infer tail extends PropertyKey[], +] + ? head extends keyof input + ? getPath + : undefined + : input; + +export function getPath(input: input, path: path): getPath { + return path.length ? (getPath(get(input, path[0]), path.slice(1)) as never) : (input as never); } export function hasOwnKey( @@ -39,5 +49,5 @@ export function mergeIfUndefined( const allKeys = [...new Set([...Object.keys(base), ...Object.keys(merged)])]; return Object.fromEntries( allKeys.map((key) => [key, base[key as keyof base] ?? merged[key as keyof merged]]), - ) as mergeIfUndefined; + ) as never; } diff --git a/packages/store/ts/config/v2/input.ts b/packages/store/ts/config/v2/input.ts index 4fec0c9298..07a36188d7 100644 --- a/packages/store/ts/config/v2/input.ts +++ b/packages/store/ts/config/v2/input.ts @@ -1,6 +1,7 @@ import { Hex } from "viem"; import { Codegen, Enums, TableCodegen, TableDeploy, UserTypes } from "./output"; import { Scope } from "./scope"; +import { evaluate } from "@arktype/util"; export type SchemaInput = { readonly [key: string]: string; @@ -41,4 +42,4 @@ export type TablesWithShorthandsInput = { readonly [key: string]: TableInput | TableShorthandInput; }; -export type StoreWithShorthandsInput = Omit & { tables: TablesWithShorthandsInput }; +export type StoreWithShorthandsInput = evaluate & { tables: TablesWithShorthandsInput }>; diff --git a/packages/store/ts/config/v2/output.ts b/packages/store/ts/config/v2/output.ts index 05dc8e8c57..23e79ad15b 100644 --- a/packages/store/ts/config/v2/output.ts +++ b/packages/store/ts/config/v2/output.ts @@ -1,3 +1,4 @@ +import { evaluate } from "@arktype/util"; import { AbiType, Schema, Table as BaseTable } from "@latticexyz/config"; export type { AbiType, Schema }; @@ -21,10 +22,12 @@ export type TableDeploy = { readonly disabled: boolean; }; -export type Table = BaseTable & { - readonly codegen: TableCodegen; - readonly deploy: TableDeploy; -}; +export type Table = evaluate< + BaseTable & { + readonly codegen: TableCodegen; + readonly deploy: TableDeploy; + } +>; export type Codegen = { readonly storeImportPath: string; diff --git a/packages/store/ts/config/v2/schema.ts b/packages/store/ts/config/v2/schema.ts index 472c6df559..099d2fd820 100644 --- a/packages/store/ts/config/v2/schema.ts +++ b/packages/store/ts/config/v2/schema.ts @@ -14,7 +14,7 @@ export type validateSchema = schema export function validateSchema( schema: unknown, - scope: scope = AbiTypeScope as unknown as scope, + scope: scope = AbiTypeScope as never, ): asserts schema is SchemaInput { if (!isObject(schema)) { throw new Error(`Expected schema, received ${JSON.stringify(schema)}`); @@ -46,13 +46,11 @@ export function resolveSchema [ key, { - type: isFixedArrayAbiType(internalType) - ? fixedArrayToArray(internalType) - : scope.types[internalType as keyof typeof scope.types], + type: isFixedArrayAbiType(internalType) ? fixedArrayToArray(internalType) : scope.types[internalType as never], internalType, }, ]), - ) as unknown as resolveSchema; + ) as never; } export function defineSchema( @@ -60,12 +58,12 @@ export function defineSchema( scope: scope = AbiTypeScope as scope, ): resolveSchema { validateSchema(schema, scope); - return resolveSchema(schema, scope) as resolveSchema; + return resolveSchema(schema, scope) as never; } export function isSchemaInput( input: unknown, - scope: scope = AbiTypeScope as unknown as scope, + scope: scope = AbiTypeScope as never, ): input is SchemaInput { return ( typeof input === "object" && diff --git a/packages/store/ts/config/v2/scope.ts b/packages/store/ts/config/v2/scope.ts index ec1ba28478..a5f70e6f5d 100644 --- a/packages/store/ts/config/v2/scope.ts +++ b/packages/store/ts/config/v2/scope.ts @@ -21,7 +21,7 @@ export type getStaticAbiTypeKeys< > = SchemaInput extends schema ? string : { - [key in keyof schema]: scope["types"][schema[key] & keyof scope["types"]] extends StaticAbiType ? key : never; + [key in keyof schema]: scope["types"] extends { [_ in schema[key]]: StaticAbiType } ? key : never; }[keyof schema]; export type extendScope> = evaluate< diff --git a/packages/store/ts/config/v2/store.ts b/packages/store/ts/config/v2/store.ts index 6e74f3ca54..2305f2fba4 100644 --- a/packages/store/ts/config/v2/store.ts +++ b/packages/store/ts/config/v2/store.ts @@ -1,4 +1,4 @@ -import { evaluate, narrow } from "@arktype/util"; +import { flatMorph, narrow } from "@arktype/util"; import { get, hasOwnKey, mergeIfUndefined } from "./generics"; import { UserTypes } from "./output"; import { CONFIG_DEFAULTS } from "./defaults"; @@ -37,13 +37,13 @@ export function validateStore(store: unknown): asserts store is StoreInput { } } -type keyPrefix = "namespace" extends keyof store - ? store["namespace"] extends "" +type keyPrefix = store extends { namespace: infer namespace extends string } + ? namespace extends "" ? "" - : `${store["namespace"] & string}__` + : `${namespace}__` : ""; -export type resolveStore = evaluate<{ +export type resolveStore = { readonly tables: "tables" extends keyof store ? resolveTables< { @@ -57,29 +57,27 @@ export type resolveStore = evaluate<{ : {}; readonly userTypes: "userTypes" extends keyof store ? store["userTypes"] : {}; readonly enums: "enums" extends keyof store ? resolveEnums : {}; - readonly namespace: "namespace" extends keyof store ? store["namespace"] : (typeof CONFIG_DEFAULTS)["namespace"]; + readonly namespace: "namespace" extends keyof store ? store["namespace"] : CONFIG_DEFAULTS["namespace"]; readonly codegen: "codegen" extends keyof store ? resolveCodegen : resolveCodegen<{}>; -}>; +}; export function resolveStore(store: store): resolveStore { return { tables: resolveTables( - Object.fromEntries( - Object.entries(store.tables ?? {}).map(([tableKey, table]) => { - const key = store.namespace ? `${store.namespace}__${tableKey}` : tableKey; - return [key, mergeIfUndefined(table, { namespace: store.namespace, name: tableKey })]; - }), - ), + flatMorph(store.tables ?? {}, (tableKey, table) => { + const key = store.namespace ? `${store.namespace}__${tableKey}` : tableKey; + return [key, mergeIfUndefined(table, { namespace: store.namespace, name: tableKey })]; + }), extendedScope(store), ), userTypes: store.userTypes ?? {}, enums: store.enums ?? {}, namespace: store.namespace ?? CONFIG_DEFAULTS["namespace"], codegen: resolveCodegen(store.codegen), - } as unknown as resolveStore; + } as never; } export function defineStore(store: validateStore): resolveStore { validateStore(store); - return resolveStore(store) as unknown as resolveStore; + return resolveStore(store) as never; } diff --git a/packages/store/ts/config/v2/storeWithShorthands.ts b/packages/store/ts/config/v2/storeWithShorthands.ts index dd8a271776..c5bfeacaea 100644 --- a/packages/store/ts/config/v2/storeWithShorthands.ts +++ b/packages/store/ts/config/v2/storeWithShorthands.ts @@ -40,12 +40,12 @@ export function resolveStoreWithShorthands; + return resolveStore(fullConfig) as never; } export function defineStoreWithShorthands( store: validateStoreWithShorthands, ): resolveStoreWithShorthands { validateStoreWithShorthands(store); - return resolveStoreWithShorthands(store) as unknown as resolveStoreWithShorthands; + return resolveStoreWithShorthands(store) as never; } diff --git a/packages/store/ts/config/v2/table.ts b/packages/store/ts/config/v2/table.ts index 933cd6baad..cd5f59003b 100644 --- a/packages/store/ts/config/v2/table.ts +++ b/packages/store/ts/config/v2/table.ts @@ -1,4 +1,4 @@ -import { ErrorMessage, conform, narrow, requiredKeyOf } from "@arktype/util"; +import { ErrorMessage, conform, evaluate, narrow, requiredKeyOf } from "@arktype/util"; import { isStaticAbiType } from "@latticexyz/schema-type/internal"; import { Hex } from "viem"; import { get, hasOwnKey, mergeIfUndefined } from "./generics"; @@ -20,7 +20,7 @@ function getValidKeys { return Object.entries(schema) .filter(([, internalType]) => hasOwnKey(scope.types, internalType) && isStaticAbiType(scope.types[internalType])) - .map(([key]) => key) as unknown as ValidKeys; + .map(([key]) => key) as never; } export function isValidPrimaryKey( @@ -45,17 +45,17 @@ export type validateKeys = keys extends rea export type ValidateTableOptions = { inStoreContext: boolean }; +export type requiredTableKey = Exclude< + requiredKeyOf, + inStoreContext extends true ? "name" | "namespace" : "" +>; + export type validateTable< input, scope extends Scope = AbiTypeScope, options extends ValidateTableOptions = { inStoreContext: false }, > = { - [key in - | keyof input - | Exclude< - requiredKeyOf, - options["inStoreContext"] extends true ? "name" | "namespace" : "" - >]: key extends "key" + [key in keyof input | requiredTableKey]: key extends "key" ? validateKeys, SchemaInput>, scope>, get> : key extends "schema" ? validateSchema, scope> @@ -101,22 +101,22 @@ export function validateTable( } } -export type resolveTableCodegen = { +export type resolveTableCodegen = evaluate<{ [key in keyof TableCodegen]-?: key extends keyof input["codegen"] ? undefined extends input["codegen"][key] ? key extends "dataStruct" ? boolean - : key extends keyof typeof TABLE_CODEGEN_DEFAULTS - ? (typeof TABLE_CODEGEN_DEFAULTS)[key] + : key extends keyof TABLE_CODEGEN_DEFAULTS + ? TABLE_CODEGEN_DEFAULTS[key] : never : input["codegen"][key] : // dataStruct isn't narrowed, because its value is conditional on the number of value schema fields key extends "dataStruct" ? boolean - : key extends keyof typeof TABLE_CODEGEN_DEFAULTS - ? (typeof TABLE_CODEGEN_DEFAULTS)[key] + : key extends keyof TABLE_CODEGEN_DEFAULTS + ? TABLE_CODEGEN_DEFAULTS[key] : never; -}; +}>; export function resolveTableCodegen(input: input): resolveTableCodegen { const options = input.codegen; @@ -140,7 +140,7 @@ export type resolveTable = input extends Tab readonly codegen: resolveTableCodegen; readonly deploy: mergeIfUndefined< undefined extends input["deploy"] ? {} : input["deploy"], - typeof TABLE_DEPLOY_DEFAULTS + TABLE_DEPLOY_DEFAULTS >; } : never; @@ -163,7 +163,7 @@ export function resolveTable; + } as never; } export function defineTable( @@ -171,5 +171,5 @@ export function defineTable( scope: scope = AbiTypeScope as unknown as scope, ): resolveTable { validateTable(input, scope); - return resolveTable(input, scope) as resolveTable; + return resolveTable(input, scope) as never; } diff --git a/packages/store/ts/config/v2/tableShorthand.test.ts b/packages/store/ts/config/v2/tableShorthand.test.ts index ea6196a1db..b3813b28d3 100644 --- a/packages/store/ts/config/v2/tableShorthand.test.ts +++ b/packages/store/ts/config/v2/tableShorthand.test.ts @@ -1,7 +1,7 @@ import { describe, it } from "vitest"; import { attest } from "@arktype/attest"; import { AbiTypeScope, extendScope } from "./scope"; -import { defineTableShorthand } from "./tableShorthand"; +import { defineTableShorthand, NoStaticKeyFieldError } from "./tableShorthand"; describe("defineTableShorthand", () => { it("should expand a single ABI type into a id/value schema", () => { @@ -146,8 +146,6 @@ describe("defineTableShorthand", () => { attest(() => // @ts-expect-error "Error: Invalid schema. Expected an `id` field with a static ABI type or an explicit `key` option." defineTableShorthand({ id: "CustomType", name: "string", age: "uint256" }, scope), - ).throwsAndHasTypeError( - "Invalid schema. Expected an `id` field with a static ABI type or an explicit `key` option.", - ); + ).throwsAndHasTypeError(NoStaticKeyFieldError); }); }); diff --git a/packages/store/ts/config/v2/tableShorthand.ts b/packages/store/ts/config/v2/tableShorthand.ts index dae5aa401e..bdbd083d14 100644 --- a/packages/store/ts/config/v2/tableShorthand.ts +++ b/packages/store/ts/config/v2/tableShorthand.ts @@ -7,8 +7,10 @@ import { SchemaInput, ScopedSchemaInput, TablesWithShorthandsInput } from "./inp import { TableShorthandInput } from "./input"; import { ValidateTableOptions, validateTable } from "./table"; -export type NoStaticKeyFieldError = - ErrorMessage<"Invalid schema. Expected an `id` field with a static ABI type or an explicit `key` option.">; +export const NoStaticKeyFieldError = + "Invalid schema. Expected an `id` field with a static ABI type or an explicit `key` option."; + +export type NoStaticKeyFieldError = ErrorMessage; export function isTableShorthandInput(shorthand: unknown): shorthand is TableShorthandInput { return ( @@ -43,7 +45,7 @@ export type validateTableShorthand = export function validateTableShorthand( shorthand: unknown, - scope: scope = AbiTypeScope as unknown as scope, + scope: scope = AbiTypeScope as never, ): asserts shorthand is TableShorthandInput { if (typeof shorthand === "string") { if (isFixedArrayAbiType(shorthand) || hasOwnKey(scope.types, shorthand)) { @@ -76,13 +78,13 @@ export type resolveTableShorthand export function resolveTableShorthand( shorthand: shorthand, - scope: scope = AbiTypeScope as unknown as scope, + scope: scope = AbiTypeScope as never, ): resolveTableShorthand { if (isSchemaInput(shorthand, scope)) { return { schema: shorthand, key: ["id"], - } as unknown as resolveTableShorthand; + } as never; } return { @@ -91,15 +93,15 @@ export function resolveTableShorthand; + } as never; } export function defineTableShorthand( shorthand: validateTableShorthand, - scope: scope = AbiTypeScope as unknown as scope, + scope: scope = AbiTypeScope as never, ): resolveTableShorthand { validateTableShorthand(shorthand, scope); - return resolveTableShorthand(shorthand, scope) as resolveTableShorthand; + return resolveTableShorthand(shorthand, scope) as never; } /** diff --git a/packages/store/ts/config/v2/tables.ts b/packages/store/ts/config/v2/tables.ts index 673b9b20d9..3e25809b91 100644 --- a/packages/store/ts/config/v2/tables.ts +++ b/packages/store/ts/config/v2/tables.ts @@ -39,5 +39,5 @@ export function resolveTables { return [key, resolveTable(mergeIfUndefined(table, { name: key }), scope)]; }), - ) as unknown as resolveTables; + ) as never; } diff --git a/packages/store/ts/config/v2/userTypes.ts b/packages/store/ts/config/v2/userTypes.ts index f038be84f0..9d83ac9c8f 100644 --- a/packages/store/ts/config/v2/userTypes.ts +++ b/packages/store/ts/config/v2/userTypes.ts @@ -24,10 +24,7 @@ export function scopeWithUserTypes { - return (isUserTypes(userTypes) ? extendScope(scope, extractInternalType(userTypes)) : scope) as scopeWithUserTypes< - userTypes, - scope - >; + return (isUserTypes(userTypes) ? extendScope(scope, extractInternalType(userTypes)) : scope) as never; } export function validateUserTypes(userTypes: unknown): asserts userTypes is UserTypes { diff --git a/packages/store/ts/register/typeExtensions.ts b/packages/store/ts/register/typeExtensions.ts index 8ffc0b2c81..a0839abfae 100644 --- a/packages/store/ts/register/typeExtensions.ts +++ b/packages/store/ts/register/typeExtensions.ts @@ -20,18 +20,9 @@ declare module "@latticexyz/config/library" { } // store-specific helper to preserve strong types, depends on store's type extensions to the core config -export interface ExpandMUDUserConfig - extends OrDefaults< - T, - { - enums: typeof DEFAULTS.enums; - userTypes: typeof DEFAULTS.userTypes; - namespace: typeof DEFAULTS.namespace; - storeImportPath: typeof PATH_DEFAULTS.storeImportPath; - userTypesFilename: typeof PATH_DEFAULTS.userTypesFilename; - codegenDirectory: typeof PATH_DEFAULTS.codegenDirectory; - codegenIndexFilename: typeof PATH_DEFAULTS.codegenIndexFilename; - } - > { +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore this doesn't cause an error I can reproduce in-editor but fails on TSC with a complaint +// about a systems prop that is not being extended +export interface ExpandMUDUserConfig extends OrDefaults { tables: ExpandTablesConfig; } diff --git a/packages/world/package.json b/packages/world/package.json index 98f13e5479..c582b031c8 100644 --- a/packages/world/package.json +++ b/packages/world/package.json @@ -54,7 +54,7 @@ "test:ci": "pnpm run test" }, "dependencies": { - "@arktype/util": "0.0.27", + "@arktype/util": "0.0.29", "@latticexyz/common": "workspace:*", "@latticexyz/config": "workspace:*", "@latticexyz/protocol-parser": "workspace:*", diff --git a/packages/world/ts/config/defaults.ts b/packages/world/ts/config/defaults.ts index b30e21ff20..a6f33553e0 100644 --- a/packages/world/ts/config/defaults.ts +++ b/packages/world/ts/config/defaults.ts @@ -4,6 +4,8 @@ export const SYSTEM_DEFAULTS = { accessList: [] as string[], } as const; +export type SYSTEM_DEFAULTS = typeof SYSTEM_DEFAULTS; + export const WORLD_DEFAULTS = { worldContractName: undefined, worldInterfaceName: "IWorld", @@ -16,3 +18,5 @@ export const WORLD_DEFAULTS = { worldImportPath: "@latticexyz/world/src/", modules: [] as [], } as const; + +export type WORLD_DEFAULTS = typeof WORLD_DEFAULTS; diff --git a/packages/world/ts/config/types.ts b/packages/world/ts/config/types.ts index 187db4c5f2..70825876f8 100644 --- a/packages/world/ts/config/types.ts +++ b/packages/world/ts/config/types.ts @@ -34,11 +34,11 @@ export interface ExpandSystemConfig { - accessList: T extends { accessList: string[] } ? T["accessList"] : typeof SYSTEM_DEFAULTS.accessList; + accessList: T extends { accessList: string[] } ? T["accessList"] : SYSTEM_DEFAULTS["accessList"]; } export type SystemsUserConfig = Record; diff --git a/packages/world/ts/config/v2/codegen.ts b/packages/world/ts/config/v2/codegen.ts index 1f7d797182..3c216d98c6 100644 --- a/packages/world/ts/config/v2/codegen.ts +++ b/packages/world/ts/config/v2/codegen.ts @@ -2,11 +2,9 @@ import { isObject, mergeIfUndefined } from "@latticexyz/store/config/v2"; import { CODEGEN_DEFAULTS } from "./defaults"; export type resolveCodegen = codegen extends {} - ? mergeIfUndefined - : typeof CODEGEN_DEFAULTS; + ? mergeIfUndefined + : CODEGEN_DEFAULTS; export function resolveCodegen(codegen: codegen): resolveCodegen { - return ( - isObject(codegen) ? mergeIfUndefined(codegen, CODEGEN_DEFAULTS) : CODEGEN_DEFAULTS - ) as resolveCodegen; + return (isObject(codegen) ? mergeIfUndefined(codegen, CODEGEN_DEFAULTS) : CODEGEN_DEFAULTS) as never; } diff --git a/packages/world/ts/config/v2/compat.ts b/packages/world/ts/config/v2/compat.ts index bb1c3b457e..95a7850a90 100644 --- a/packages/world/ts/config/v2/compat.ts +++ b/packages/world/ts/config/v2/compat.ts @@ -12,7 +12,7 @@ function modulesToV1(modules: modules): modul name: module.name, root: module.root ?? false, args: module.args ?? [], - })) as modulesToV1; + })) as never; } type systemsToV1 = { @@ -56,5 +56,5 @@ export function worldToV1(world: conform): worldToV1 worldImportPath: world.codegen.worldImportPath, }; - return { ...storeToV1(world as Store), ...v1WorldConfig, v2: world } as worldToV1; + return { ...storeToV1(world as Store), ...v1WorldConfig, v2: world } as never; } diff --git a/packages/world/ts/config/v2/defaults.ts b/packages/world/ts/config/v2/defaults.ts index 8204edc3a8..2b8f0b5a70 100644 --- a/packages/world/ts/config/v2/defaults.ts +++ b/packages/world/ts/config/v2/defaults.ts @@ -4,12 +4,16 @@ export const SYSTEM_DEFAULTS = { accessList: [] as string[], } as const; +export type SYSTEM_DEFAULTS = typeof SYSTEM_DEFAULTS; + export const CODEGEN_DEFAULTS = { worldInterfaceName: "IWorld", worldgenDirectory: "world", worldImportPath: "@latticexyz/world/src/", } as const; +export type CODEGEN_DEFAULTS = typeof CODEGEN_DEFAULTS; + export const DEPLOY_DEFAULTS = { customWorldContract: undefined, postDeployScript: "PostDeploy", @@ -17,6 +21,8 @@ export const DEPLOY_DEFAULTS = { worldsFile: "./worlds.json", } as const; +export type DEPLOY_DEFAULTS = typeof DEPLOY_DEFAULTS; + export const CONFIG_DEFAULTS = { systems: {}, tables: {}, @@ -25,3 +31,5 @@ export const CONFIG_DEFAULTS = { codegen: CODEGEN_DEFAULTS, deploy: DEPLOY_DEFAULTS, } as const; + +export type CONFIG_DEFAULTS = typeof CONFIG_DEFAULTS; diff --git a/packages/world/ts/config/v2/deploy.ts b/packages/world/ts/config/v2/deploy.ts index bfb4e81f54..3b6c65ec1f 100644 --- a/packages/world/ts/config/v2/deploy.ts +++ b/packages/world/ts/config/v2/deploy.ts @@ -1,10 +1,8 @@ import { mergeIfUndefined, isObject } from "@latticexyz/store/config/v2"; import { DEPLOY_DEFAULTS } from "./defaults"; -export type resolveDeploy = deploy extends {} - ? mergeIfUndefined - : typeof DEPLOY_DEFAULTS; +export type resolveDeploy = deploy extends {} ? mergeIfUndefined : DEPLOY_DEFAULTS; export function resolveDeploy(deploy: deploy): resolveDeploy { - return (isObject(deploy) ? mergeIfUndefined(deploy, DEPLOY_DEFAULTS) : DEPLOY_DEFAULTS) as resolveDeploy; + return (isObject(deploy) ? mergeIfUndefined(deploy, DEPLOY_DEFAULTS) : DEPLOY_DEFAULTS) as never; } diff --git a/packages/world/ts/config/v2/namespaces.ts b/packages/world/ts/config/v2/namespaces.ts index b1132e2b81..c04d3bc292 100644 --- a/packages/world/ts/config/v2/namespaces.ts +++ b/packages/world/ts/config/v2/namespaces.ts @@ -6,16 +6,17 @@ import { hasOwnKey, resolveTable, mergeIfUndefined, - get, extendedScope, + getPath, } from "@latticexyz/store/config/v2"; import { NamespacesInput } from "./input"; -export type namespacedTableKeys = "namespaces" extends keyof world - ? "tables" extends keyof world["namespaces"][keyof world["namespaces"]] - ? `${keyof world["namespaces"] & string}__${keyof world["namespaces"][keyof world["namespaces"]]["tables"] & - string}` - : never +export type namespacedTableKeys = world extends { namespaces: infer namespaces } + ? { + [k in keyof namespaces]: namespaces[k] extends { tables: infer tables } + ? `${k & string}__${keyof tables & string}` + : never; + }[keyof namespaces] : never; export type validateNamespaces = { @@ -47,7 +48,7 @@ export type resolveNamespacedTables = "namespaces" extends keyof world readonly [key in namespacedTableKeys]: key extends `${infer namespace}__${infer table}` ? resolveTable< mergeIfUndefined< - get, namespace>, "tables">, table>, + getPath, { name: table; namespace: namespace } >, extendedScope diff --git a/packages/world/ts/config/v2/world.ts b/packages/world/ts/config/v2/world.ts index 12295ea4e3..13898d5542 100644 --- a/packages/world/ts/config/v2/world.ts +++ b/packages/world/ts/config/v2/world.ts @@ -67,7 +67,7 @@ export type resolveWorld = evaluate< }, "namespaces" | keyof Store >, - typeof CONFIG_DEFAULTS + CONFIG_DEFAULTS > >; @@ -102,10 +102,10 @@ export function resolveWorld(world: world): reso modules: world.modules, }, CONFIG_DEFAULTS, - ) as unknown as resolveWorld; + ) as never; } export function defineWorld(world: validateWorld): resolveWorld { validateWorld(world); - return resolveWorld(world) as unknown as resolveWorld; + return resolveWorld(world) as never; } diff --git a/packages/world/ts/config/v2/worldWithShorthands.ts b/packages/world/ts/config/v2/worldWithShorthands.ts index 345a84d9a7..2cf35c591e 100644 --- a/packages/world/ts/config/v2/worldWithShorthands.ts +++ b/packages/world/ts/config/v2/worldWithShorthands.ts @@ -1,19 +1,19 @@ +import { mapObject } from "@latticexyz/common/utils"; import { AbiTypeScope, + Scope, extendedScope, - get, + getPath, hasOwnKey, isObject, isTableShorthandInput, resolveTableShorthand, resolveTablesWithShorthands, validateTablesWithShorthands, - Scope, } from "@latticexyz/store/config/v2"; -import { mapObject } from "@latticexyz/common/utils"; -import { resolveWorld, validateWorld } from "./world"; import { WorldWithShorthandsInput } from "./input"; import { validateNamespaces } from "./namespaces"; +import { resolveWorld, validateWorld } from "./world"; export type resolveWorldWithShorthands = resolveWorld<{ [key in keyof world]: key extends "tables" @@ -45,7 +45,7 @@ function validateWorldWithShorthands(world: unknown): asserts world is WorldWith if (hasOwnKey(world, "namespaces") && isObject(world.namespaces)) { for (const namespaceKey of Object.keys(world.namespaces)) { - validateTablesWithShorthands(get(get(world.namespaces, namespaceKey), "tables") ?? {}, scope); + validateTablesWithShorthands(getPath(world.namespaces, [namespaceKey, "tables"]) ?? {}, scope); } } } @@ -75,12 +75,12 @@ export function resolveWorldWithShorthands; + return resolveWorld(fullConfig) as never; } export function defineWorldWithShorthands( world: validateWorldWithShorthands, ): resolveWorldWithShorthands { validateWorldWithShorthands(world); - return resolveWorldWithShorthands(world) as unknown as resolveWorldWithShorthands; + return resolveWorldWithShorthands(world) as never; } diff --git a/packages/world/ts/register/typeExtensions.ts b/packages/world/ts/register/typeExtensions.ts index 8a1232c76a..fae7d77edb 100644 --- a/packages/world/ts/register/typeExtensions.ts +++ b/packages/world/ts/register/typeExtensions.ts @@ -22,21 +22,7 @@ declare module "@latticexyz/config/library" { } declare module "@latticexyz/store/register" { - export interface ExpandMUDUserConfig - extends OrDefaults< - T, - { - worldContractName: typeof WORLD_DEFAULTS.worldContractName; - worldInterfaceName: typeof WORLD_DEFAULTS.worldInterfaceName; - excludeSystems: typeof WORLD_DEFAULTS.excludeSystems; - postDeployScript: typeof WORLD_DEFAULTS.postDeployScript; - deploysDirectory: typeof WORLD_DEFAULTS.deploysDirectory; - worldsFile: typeof WORLD_DEFAULTS.worldsFile; - worldgenDirectory: typeof WORLD_DEFAULTS.worldgenDirectory; - worldImportPath: typeof WORLD_DEFAULTS.worldImportPath; - modules: typeof WORLD_DEFAULTS.modules; - } - > { + export interface ExpandMUDUserConfig extends OrDefaults { systems: ExpandSystemsConfig ? T["systems"] : Record>; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e666fe65d..ca7976c720 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -733,8 +733,8 @@ importers: packages/store: dependencies: '@arktype/util': - specifier: 0.0.27 - version: 0.0.27 + specifier: 0.0.29 + version: 0.0.29 '@latticexyz/common': specifier: workspace:* version: link:../common @@ -1028,8 +1028,8 @@ importers: packages/world: dependencies: '@arktype/util': - specifier: 0.0.27 - version: 0.0.27 + specifier: 0.0.29 + version: 0.0.29 '@latticexyz/common': specifier: workspace:* version: link:../common @@ -1254,8 +1254,8 @@ packages: resolution: {integrity: sha512-MwtDGjbgfXWxlExjIL78HvPlWOma1XFEcDd3VWuCPMt/f+3TR7fXyiGFNlIYZGOYdOIU7qgjaE8dmbd6jdJa3Q==} dev: true - /@arktype/util@0.0.27: - resolution: {integrity: sha512-ZkPuSU8Q56YVgPInFhojLTujejM+VPfaZx6Guop41CvnozWFOTlC0uAHuDqvY4nYq3zXsMkRwm8LmaRZ3mslMg==} + /@arktype/util@0.0.29: + resolution: {integrity: sha512-fDTBSVzxLj9k1ZjinkawmaQdcXFKMBVK8c+vqMPxwoa94mPMZxBo84yQcqyFVcIcWIkg6qQQmH1ozyT4nqFT/g==} dev: false /@babel/code-frame@7.21.4: