diff --git a/.changeset/tangy-apples-read.md b/.changeset/tangy-apples-read.md new file mode 100644 index 00000000..de7882ab --- /dev/null +++ b/.changeset/tangy-apples-read.md @@ -0,0 +1,5 @@ +--- +"abitype": patch +--- + +feat: support custom names in experimental_namedTuples register option diff --git a/docs/pages/config.md b/docs/pages/config.md index 2dc703e9..4468e2fa 100644 --- a/docs/pages/config.md +++ b/docs/pages/config.md @@ -155,9 +155,9 @@ declare module 'abitype' { ### `experimental_namedTuples` -Enables named tuple generation in [`AbiParametersToPrimitiveTypes`](/api/utilities#abiparameterstoprimitivetypes) for common ABI parameter names. +Enables named tuple generation in [`AbiParametersToPrimitiveTypes`](/api/utilities#abiparameterstoprimitivetypes) for common ABI parameter names. When a string array, adds custom names. -- Type `boolean` +- Type `boolean | readonly string[]` - Default `false` ```ts twoslash diff --git a/packages/abitype/src/register.test-d.ts b/packages/abitype/src/register.test-d.ts index b1012926..9bf414a9 100644 --- a/packages/abitype/src/register.test-d.ts +++ b/packages/abitype/src/register.test-d.ts @@ -24,4 +24,7 @@ test('ResolvedRegister', () => { type StrictAbiType = ResolvedRegister['strictAbiType'] assertType(false) + + type ExperimentalNamedTuples = ResolvedRegister['experimental_namedTuples'] + assertType(false) }) diff --git a/packages/abitype/src/register.ts b/packages/abitype/src/register.ts index f2ed7695..459ca9c6 100644 --- a/packages/abitype/src/register.ts +++ b/packages/abitype/src/register.ts @@ -89,12 +89,11 @@ export type ResolvedRegister = { : DefaultRegister['fixedArrayMaxLength'] /** - * Enables named tuple generation in {@link AbiParametersToPrimitiveTypes} for common ABI parameter names. - * + * Enables named tuple generation in {@link AbiParametersToPrimitiveTypes} for common ABI parameter names. When a string array, adds custom names. * @default false */ experimental_namedTuples: Register extends { - experimental_namedTuples: infer type extends boolean + experimental_namedTuples: infer type extends boolean | readonly string[] } ? type : DefaultRegister['experimental_namedTuples'] diff --git a/packages/abitype/src/utils.ts b/packages/abitype/src/utils.ts index 0b707a2f..49ef5ead 100644 --- a/packages/abitype/src/utils.ts +++ b/packages/abitype/src/utils.ts @@ -191,10 +191,17 @@ export type AbiParametersToPrimitiveTypes< abiParameterKind extends AbiParameterKind = AbiParameterKind, /// experimental_namedTuples extends - boolean = ResolvedRegister['experimental_namedTuples'], -> = experimental_namedTuples extends true - ? AbiParametersToPrimitiveTypes_named - : AbiParametersToPrimitiveTypes_mapped + | boolean + | readonly string[] = ResolvedRegister['experimental_namedTuples'], +> = experimental_namedTuples extends false + ? AbiParametersToPrimitiveTypes_mapped + : AbiParametersToPrimitiveTypes_named< + abiParameters, + abiParameterKind, + experimental_namedTuples extends readonly string[] + ? experimental_namedTuples + : readonly [] + > export type AbiParametersToPrimitiveTypes_mapped< abiParameters extends readonly AbiParameter[], @@ -209,6 +216,7 @@ export type AbiParametersToPrimitiveTypes_mapped< export type AbiParametersToPrimitiveTypes_named< abiParameters extends readonly AbiParameter[], abiParameterKind extends AbiParameterKind = AbiParameterKind, + customNames extends readonly string[] = readonly [], /// acc extends readonly unknown[] = [], depth extends readonly number[] = [], @@ -231,14 +239,15 @@ export type AbiParametersToPrimitiveTypes_named< ? AbiParametersToPrimitiveTypes_named< tail, abiParameterKind, + customNames, readonly [ ...acc, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, ], [...depth, 1] > @@ -251,11 +260,11 @@ export type AbiParametersToPrimitiveTypes_named< ] ? readonly [ ...acc, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, ] : abiParameters extends readonly [ infer head1 extends AbiParameter, @@ -265,10 +274,10 @@ export type AbiParametersToPrimitiveTypes_named< ] ? readonly [ ...acc, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, ] : abiParameters extends readonly [ infer head1 extends AbiParameter, @@ -277,9 +286,9 @@ export type AbiParametersToPrimitiveTypes_named< ] ? readonly [ ...acc, - ...ToNamedTuple, - ...ToNamedTuple, - ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, ] : abiParameters extends readonly [ infer head1 extends AbiParameter, @@ -287,11 +296,14 @@ export type AbiParametersToPrimitiveTypes_named< ] ? readonly [ ...acc, - ...ToNamedTuple, - ...ToNamedTuple, + ...ToNamedTuple, + ...ToNamedTuple, ] : abiParameters extends readonly [infer head extends AbiParameter] - ? readonly [...acc, ...ToNamedTuple] + ? readonly [ + ...acc, + ...ToNamedTuple, + ] : acc extends readonly [] ? abiParameters extends readonly [] ? readonly [] @@ -301,12 +313,31 @@ export type AbiParametersToPrimitiveTypes_named< type ToNamedTuple< abiParameter extends AbiParameter, abiParameterKind extends AbiParameterKind, + customNames extends readonly string[] = readonly [], > = unwrapName< AbiParameterToPrimitiveType, - abiParameter['name'] + abiParameter['name'], + customNames > -type unwrapName = name extends string - ? AbiParameterTupleNameLookup[name] + +type CustomTupleNameLookup< + type, + customNames extends readonly string[], +> = customNames extends readonly [] + ? {} + : { [K in customNames[number]]: [K: type] } + +type MergedTupleNameLookup< + type, + customNames extends readonly string[], +> = AbiParameterTupleNameLookup & CustomTupleNameLookup + +type unwrapName< + type, + name, + customNames extends readonly string[] = readonly [], +> = name extends string + ? MergedTupleNameLookup[name] : [type] /** diff --git a/packages/register-tests/named-tuples/package.json b/packages/register-tests/named-tuples/package.json new file mode 100644 index 00000000..6494e34d --- /dev/null +++ b/packages/register-tests/named-tuples/package.json @@ -0,0 +1,11 @@ +{ + "name": "named-tuples-register", + "private": true, + "type": "module", + "scripts": { + "check:types": "tsc --noEmit" + }, + "dependencies": { + "abitype": "workspace:*" + } +} diff --git a/packages/register-tests/named-tuples/src/named-tuples.test-d.ts b/packages/register-tests/named-tuples/src/named-tuples.test-d.ts new file mode 100644 index 00000000..5370128f --- /dev/null +++ b/packages/register-tests/named-tuples/src/named-tuples.test-d.ts @@ -0,0 +1,40 @@ +import type { AbiParametersToPrimitiveTypes } from 'abitype' +import { describe, expectTypeOf, test } from 'vitest' + +describe('experimental_namedTuples', () => { + test('common names', () => { + type Result = AbiParametersToPrimitiveTypes< + [{ name: 'amount'; type: 'uint256' }] + > + expectTypeOf().toEqualTypeOf() + }) + + test('custom names', () => { + type Result1 = AbiParametersToPrimitiveTypes< + [{ name: 'myCustomParam'; type: 'uint256' }] + > + expectTypeOf().toEqualTypeOf() + + type Result2 = AbiParametersToPrimitiveTypes< + [{ name: 'projectSpecificName'; type: 'address' }] + > + expectTypeOf().toEqualTypeOf< + readonly [projectSpecificName: `0x${string}`] + >() + + type Mixed = AbiParametersToPrimitiveTypes< + [ + { name: 'myCustomParam'; type: 'uint256' }, + { name: 'amount'; type: 'uint256' }, + { name: 'projectSpecificName'; type: 'address' }, + ] + > + expectTypeOf().toEqualTypeOf< + readonly [ + myCustomParam: bigint, + amount: bigint, + projectSpecificName: `0x${string}`, + ] + >() + }) +}) diff --git a/packages/register-tests/named-tuples/src/register.ts b/packages/register-tests/named-tuples/src/register.ts new file mode 100644 index 00000000..c2d94167 --- /dev/null +++ b/packages/register-tests/named-tuples/src/register.ts @@ -0,0 +1,5 @@ +declare module 'abitype' { + interface Register { + experimental_namedTuples: ['myCustomParam', 'projectSpecificName'] + } +} diff --git a/packages/register-tests/named-tuples/tsconfig.json b/packages/register-tests/named-tuples/tsconfig.json new file mode 100644 index 00000000..77a211db --- /dev/null +++ b/packages/register-tests/named-tuples/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": [] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc2ce87e..1a7805dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -100,6 +100,12 @@ importers: specifier: workspace:* version: link:../../abitype + packages/register-tests/named-tuples: + dependencies: + abitype: + specifier: workspace:* + version: link:../../abitype + playgrounds/functions: dependencies: abitype: