Skip to content

Commit

Permalink
ts: Improve IDL typing (#2482)
Browse files Browse the repository at this point in the history
* Use XOR pattern for enum variants to prevent two variants being used at the same time.

* Fix unknown for types like Option<[u8; 32]>
  • Loading branch information
Juici authored May 8, 2023
1 parent d1ddf00 commit 9a93a2e
Showing 1 changed file with 25 additions and 23 deletions.
48 changes: 25 additions & 23 deletions ts/packages/anchor/src/program/namespace/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,24 +124,20 @@ type TypeMap = {
[K in "u64" | "i64" | "u128" | "i128" | "u256" | "i256"]: BN;
};

export type DecodeType<T extends IdlType, Defined> = T extends keyof TypeMap
export type DecodeType<T extends IdlType, Defined> = IdlType extends T
? unknown
: T extends keyof TypeMap
? TypeMap[T]
: T extends { defined: keyof Defined }
? Defined[T["defined"]]
: T extends { option: { defined: keyof Defined } }
? Defined[T["option"]["defined"]] | null
: T extends { option: keyof TypeMap }
? TypeMap[T["option"]] | null
: T extends { coption: { defined: keyof Defined } }
? Defined[T["coption"]["defined"]] | null
: T extends { coption: keyof TypeMap }
? TypeMap[T["coption"]] | null
: T extends { vec: keyof TypeMap }
? TypeMap[T["vec"]][]
: T extends { vec: { defined: keyof Defined } }
? Defined[T["vec"]["defined"]][]
: T extends { array: [defined: keyof TypeMap, size: number] }
? TypeMap[T["array"][0]][]
: T extends { option: IdlType }
? DecodeType<T["option"], Defined> | null
: T extends { coption: IdlType }
? DecodeType<T["coption"], Defined> | null
: T extends { vec: IdlType }
? DecodeType<T["vec"], Defined>[]
: T extends { array: [defined: IdlType, size: number] }
? DecodeType<T["array"][0], Defined>[]
: unknown;

/**
Expand Down Expand Up @@ -196,18 +192,24 @@ declare type DecodeEnumFields<
}
: Record<string, never>;

/**
* Since TypeScript do not provide OneOf helper we can
* simply mark enum variants with +?
*/
declare type DecodeEnum<K extends IdlTypeDefTyEnum, Defined> = {
// X = IdlEnumVariant
[X in K["variants"][number] as Uncapitalize<X["name"]>]+?: DecodeEnumFields<
NonNullable<X["fields"]>,
type DecodeEnumVariants<I extends IdlTypeDefTyEnum, Defined> = {
[V in I["variants"][number] as Uncapitalize<V["name"]>]: DecodeEnumFields<
NonNullable<V["fields"]>,
Defined
>;
};

type ValueOf<T> = T[keyof T];
type XorEnumVariants<T extends Record<string, unknown>> = ValueOf<{
[K1 in keyof T]: {
[K2 in Exclude<keyof T, K1>]?: never;
} & { [K2 in K1]: T[K2] };
}>;

type DecodeEnum<I extends IdlTypeDefTyEnum, Defined> = XorEnumVariants<
DecodeEnumVariants<I, Defined>
>;

type DecodeStruct<I extends IdlTypeDefTyStruct, Defined> = {
[F in I["fields"][number] as F["name"]]: DecodeType<F["type"], Defined>;
};
Expand Down

1 comment on commit 9a93a2e

@vercel
Copy link

@vercel vercel bot commented on 9a93a2e May 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

anchor-docs – ./

www.anchor-lang.com
anchor-docs-git-master-200ms.vercel.app
anchor-lang.com
anchor-docs-200ms.vercel.app

Please sign in to comment.