Skip to content
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

Add support to Option<T> #470

Closed
2 tasks done
luizstacio opened this issue Aug 23, 2022 · 4 comments · Fixed by #471
Closed
2 tasks done

Add support to Option<T> #470

luizstacio opened this issue Aug 23, 2022 · 4 comments · Fixed by #471

Comments

@luizstacio
Copy link
Member

luizstacio commented Aug 23, 2022

Description

Today if a contract uses the sway object Option<T> as a return or argument of a function, we parse it as a custom Enum from the ABI, requiring the user to take action and pass an object { None: [] } or { Some: <value> } to match the custom enum.

The ideal implementation of Option<T> on typescript would be to abstract the enum Option and;

  • In case of argument: simplify the argument to be the valid value (T) or optional in this case, null or undefined.
  • On the return: we should return the value T or null/undefined.

Todos;

  • Implement an abstraction for the Option<T> by identifying it from the json ABI.
  • Add the abstraction type inside the typechain to match the implementation.

Use case

Contract

contract;

use std::{option::Option};

abi MyContract {
  fn test_option(param: Option<u32>) -> Option<u32>;
}

impl MyContract for Contract {
  fn test_option(param: Option<u32>) -> Option<u32> {
    param
  }
}

Current way on Typescript

// When calling the contract, we require the user to 
// create an object { None: [] } for no params and { Some: 12 }
// when it will provide the value.
const { value } = await contract.functions
  .test_option({
    None: [],
  })
  .call();
// value will be {  None: [] }
const { value } = await contract.functions
  .test_option({
    Some: 12,
  })
  .call();
// value will be {  Some: 12 }

Desired implementation on Typescript

// When calling the contract that has a params Option<T>, 
// we can make the param optional and create the underlining abstraction
// to create the correct params object { None: [] } or { Some: 12 }
const { value } = await contract.functions
  .test_option()
  .call();
// value will be null
const { value } = await contract.functions
  .test_option(12)
  .call();
// value will be 12
@camsjams
Copy link
Contributor

camsjams commented Aug 24, 2022

I'd like to say as a preference and also to match up with fp-ts and other functional programming styles, that in JS its nicer to have an Option be like:

type Option<T> = T | undefined;

As is in more strict and no null

@luizstacio
Copy link
Member Author

I'd like to say as a preference and also to match up with fp-ts and other functional programming styles, that in JS its nicer to have an Option be like:

type Option<T> = T | undefined;

As is in more strict and no null

I think the issue with this is that the user will need to provide undefined value when don't want to pass anything.

type Option<T> = T | undefined;

function foo(o: Option<number>) {
    console.log(o);
}

foo();

Would result in;
Screen Shot 2022-08-24 at 4 10 00 PM

@camsjams
Copy link
Contributor

camsjams commented Aug 26, 2022

The same occurs for a type with null | undefined like this (see TypeScript Playground)

type PossiblyUndefined = number | undefined; 
// or type PossiblyUndefined = number | null | undefined;
function bar(o: PossiblyUndefined) {
    console.log(o);
}

bar();

But in original code, this should be more like:

type Option<T> = T | undefined;

function foo(o: Option<number>) {
    console.log(o);
}

let val: Option<number> = undefined;
foo(val);
// and
foo(undefined);
foo(undefined as Option<number>);
foo(1);
foo(2 as Option<number>)

// or change signature
function foo(o?: Option<number>) {
    console.log(o);
}

// or
function foo(o: Option<number> = undefined) {
    console.log(o);
}

Which is verifying via the Option type

@luizstacio
Copy link
Member Author

The same occurs for a type with null | undefined like this (see TypeScript Playground)

type PossiblyUndefined = number | undefined; 
// or type PossiblyUndefined = number | null | undefined;
function bar(o: PossiblyUndefined) {
    console.log(o);
}

bar();

But in original code, this should be more like:

type Option<T> = T | undefined;

function foo(o: Option<number>) {
    console.log(o);
}

let val: Option<number> = undefined;
foo(val);
// and
foo(undefined);
foo(undefined as Option<number>);
foo(1);
foo(2 as Option<number>)

// or change signature
function foo(o?: Option<number>) {
    console.log(o);
}

// or
function foo(o: Option<number> = undefined) {
    console.log(o);
}

Which is verifying via the Option type

Yeah I think we need to make optional what will be mainly implemented on TypeChain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants