DEV Community

David Dal Busco
David Dal Busco

Posted on • Originally published at daviddalbusco.Medium

TypeScript Utilities For Candid

Photo by Georgie Cobbs on Unsplash


To port our web editor, DeckDeckGo, to DFINITY’s Internet Computer I developed several helpers in TypeScript to interact with our canister smart contracts.

If it can make your life easier too, here are those I use the most.


Nullable

The Candid description that is generated for nullable types does not exactly match what I commonly used in JavaScript for optional types (see this post for the why and how).

For example, if we generate an interface for such a Motoko code snippet:

actor Example {
  public shared query func list(filter: ?Text) : async [Text] {
    let results: [Text] = myFunction(filter);
    return results;
  };
}
Enter fullscreen mode Exit fullscreen mode

The definition of the optional parameter filter will not be interpreted as a string that can potentially be undefined but, rather as a one-element length array that contains a string or is empty.

export interface _SERVICE {
  list: (arg_0: [] | [string]) => Promise<Array<string>>;
}
Enter fullscreen mode Exit fullscreen mode

That is why I created functions to convert back and forth optional values.

export const toNullable = <T>(value?: T): [] | [T] => {
  return value ? [value] : [];
};

export const fromNullable = <T>(value: [] | [T]): T | undefined => {
  return value?.[0];
};
Enter fullscreen mode Exit fullscreen mode

toNullable convert an object that can either be of type T or undefined to what’s expected to interact with the IC and, fromNullable do the opposite.


Dates

System Time (nanoseconds since 1970–01–01) gets parsed to bigint and exported as a type Time in Candid definition.

export type Time = bigint;
Enter fullscreen mode Exit fullscreen mode

To convert JavaScript Date to big numbers, the built-in object BigInt can be instantiated.

export const toTimestamp = (value: Date): Time => {
  return BigInt(value.getTime());
};
Enter fullscreen mode Exit fullscreen mode

The other way around works by converting first the big numbers to their primitive Number types.

export const fromTimestamp = (value: Time): Date => {
  return new Date(Number(value));
};
Enter fullscreen mode Exit fullscreen mode

To support Nullable timestamps values, I also created the following helpers that extend above converters and return the appropriate optional arrays.

export const toNullableTimestamp = (value?: Date): [] | [Time] => {
  const time: number | undefined = value?.getTime();
  return value && !isNaN(time) ? [toTimestamp(value)] : [];
};

export const fromNullableTimestamp = 
       (value?: [] | [Time]): Date | undefined => {
  return !isNaN(parseInt(`${value?.[0]}`)) ? 
            new Date(`${value[0]}`) : undefined;
};
Enter fullscreen mode Exit fullscreen mode

Blob

Binary blobs are described in Candid as Array of numbers. To save untyped data in smart contracts (assuming the use case allows such risk) while still preserving types on the frontend side, we can stringify objects, converts these to blobs and gets their contents as binary data contained in an ArrayBuffer.

export const toArray = 
       async <T>(data: T): Promise<Array<number>> => {
  const blob: Blob = new Blob([JSON.stringify(data)], 
                         {type: 'application/json; charset=utf-8'});
  return [...new Uint8Array(await blob.arrayBuffer())];
};
Enter fullscreen mode Exit fullscreen mode

To convert back an Array of numbers to a specific object type, the Blob type can be used again but, this time a textual conversion shall be used to parse the results.

export const fromArray = 
       async <T>(data: Array<number>): Promise<T> => {
  const blob: Blob = new Blob([new Uint8Array(data)], 
                         {type: 'application/json; charset=utf-8'});
  return JSON.parse(await blob.text());
};
Enter fullscreen mode Exit fullscreen mode

Both conversions are asynchronous because interacting with the blob object requires resolving promises in JavaScript.


Further Reading

Wanna read more our project? Here is the list of blog posts I published since we started the project with the Internet Computer:


Keep In Touch

To follow our adventure, you can star and watch our GitHub repo ⭐️ and sign up to join the list of beta tester.


Conclusion

I hope this short blog post and few utilities will be useful for you to start well with the Internet Computer, it is really a fun technology.

To infinity and beyond!

David


You can reach me on Twitter or my website.

Give a try to DeckDeckGo for your next slides!

DeckDeckGo

Discussion (0)