-
Notifications
You must be signed in to change notification settings - Fork 80
Add generics for contract type-safety #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Hey, this is really cool! Thanks for creating this PR. This functionality would be really nice to have, we saw that there's some TODOs / refactors still needed. If we want to integrate this, then the inferring would also need to work for the We will have more bandwidth to get this implemented / integrated once the debugging tooling upgrade (v0.10) is released, so we'll get back to this issue after that. |
on commit 90191fb i use ignore that error, because we know that it must be indexed and we are setting the right value const name = f.name as keyof TFunctions;
this.functions[name] = this.createFunction(f) as TFunctions[keyof TFunctions]; |
Hey @PHCitizen, just want to write to let you know we haven't forgotten about this PR. We've finally released the debugging functionality with version 0.10.0 earlier this month. We will finally be able to pick this PR up in November. Thanks once again for the effort thusfar, and we'll work to get this integrated in November. 🙌 |
Regarding completing the
a back and forth with chatGPT suggested the following to include type GenerateBytes<N extends number, Result extends unknown[] = []> =
Result['length'] extends N
? never
: `bytes${Result['length'] | 1}` | GenerateBytes<N, [...Result, unknown]>;
// TypeMap with dynamic fixed-length byte types
type TypeMap = {
bool: boolean;
int: bigint;
string: string;
byte: Uint8Array;
bytes: Uint8Array;
[K in GenerateBytes<100>]: Uint8Array; // Generates `bytes1` to `bytes100`
pubkey: Uint8Array;
sig: Uint8Array;
datasig: Uint8Array;
}; |
ChatGPT also suggested a possible solution to the nesting in /**
* Converts an array of artifact parameters into a tuple type representing each parameter's type.
*
* Example:
* If T = [{ type: 'int' }, { type: 'bool' }], GetParameterTuple<T> resolves to [bigint, boolean].
*/
type GetParameterTuple<T> =
T extends readonly [{ type: infer ParamType }, ...infer Rest]
? [ParamType extends keyof TypeMap ? TypeMap[ParamType] : any, ...GetParameterTuple<Rest>]
: [];
|
while further trying to improve the types ChatGPT suggested sometthing similar for It needs careful review and testing! but solving the nesting looks promising for maintainability... 👀 /**
* Infers function argument types from an artifact ABI, producing a map of function names to argument tuples.
*
* Example:
* If T = [{ name: 'func', inputs: [{ type: 'int' }] }, { name: 'otherFunc', inputs: [{ type: 'bool' }] }],
* then InferContractFunction<T> resolves to { func: [bigint], otherFunc: [boolean] }
*/
type InferContractFunction<T> =
T extends readonly [{ name: infer Name, inputs: infer Inputs }, ...infer Rest]
? { [K in Name & string]: GetParameterTuple<Inputs> } & InferContractFunction<Rest>
: {}; |
does this one compile? i cant compile it. anyway i expected there that the number are fixed and did not allow arbitrary number if any number can be use i think we can use this one type TypeMap = {
[k: `bytes${number}`]: Uint8Array;
} & {
"bool": boolean;
"int": bigint;
.....
} |
Regarding to other improvement listed, i think i encounter that before and that is my first solution/attempt. Then i came to place where "any" messed all up, so i try to push it futher and ended it that code😆 But maybe im wrong? who will feed "any" on that function. Anyway i think most of the user that will ended in "any" are those who uses JS, maybe they do not need type support or im thinking if the edge case error will show/not on them will look futher soon |
You are correct, my attempt did not 😅 thanks for the correct way!
@PHCitizen it would be super helpful to also have that code if you have the typescript playground link! |
I did another attempt to simplify the typings to increase maintainability & simplicity of the typescript code. I named the generics to make it more clear what is going on. Here is the main part: class Contract<
Artifact extends { constructorInputs: readonly any[]; abi: readonly any[] } = {
constructorInputs: any[];
abi: any[];
},
ResolvedTypes extends {
constructorInputs: any[];
functions: Record<string, any>;
} = {
constructorInputs: ParamsToTuple<Artifact["constructorInputs"]>;
functions: AbiToFunctionMap<Artifact["abi"]>;
}
> {
functions!: ResolvedTypes["functions"];
constructor(artifact: Artifact, params: ResolvedTypes["constructorInputs"]) {}
} 48 lines compared to the original nested 78 but it also removes the |
On ParamsToTuple, if we pass type that dont match on the typemap, it defaults to UintArray Solution: add extends to infer instead of using type ParamsToTuple<Params> = Params extends readonly [infer Head, ...infer Tail]
? Head extends { type: infer Type extends keyof TypeMap}
? [TypeMap[Type], ...ParamsToTuple<Tail>]
: [any, ...ParamsToTuple<Tail>]
: []; and also adding i think the best way is not to return function type when using AbiToFunctionMap, instead just return the result of To make it simple, what i really intend is to simplify return type typing specifically for
AFAIK I send the initial copy somewhere, i cant remember where, i assume it's on telegram, but i forgot what channel |
I found the original on telegram! 😄 👍 https://t.me/bch_compilers/7456
|
We got started on implementing the fixes discussed by @PHCitizen and @mr-zwets above, and integrating the required changes into this PR. We also started adding tests for this type inference to the github repo, based on the test cases from the TS playground link(s) above. One difficulty we noticed is that it is impossible to import a JSON file We'll continue the work on this on Thursday, and I think we should be able to finish most of the test cases and refactors by then. And then we'll just need to think if there are better ways to mitigate the "const json" issue. |
We finished the refactors + tests, so this should be good to go. The only drawback is still that we cannot infer proper types from JSON files, so we want to add an option to the Next Tuesday we will add this option, update documentation and release this functionality. 🫡 |
Thanks @PHCitizen for this contribution. We added the |
this is the implementation of the snippets I post on telegram. Types are a bit different because I make a fallback if "any" is passed. this is needed if the user are using javascript or artifact are imported somewhere, and we cant infer the types
latest ts playground
btw i remove infer using string. i think if they will use it, much better to use interface and define type there.