3

I was trying to implement a generic function that accepts an interface of functions and data, and passes the results from one another.

Inference is broken, any help will be appreciated.

Link to a CodeSandbox of the Code That Does Not Compile

function InitViewModel<S, C, M>(params: {
  state: S;
  computed: (s: S) => C;
  methods: (s: S, c: C) => M;
}) {
  const state = params.state;
  const computed = params.computed(state);
  const methods = params.methods(state, computed);
  return {
    state,
    computed,
    methods
  };
}

export const VM = InitViewModel({
  state: { message: "This Will Be Infered As expected" },
  computed: (state /* infered */) => ({
    computedMessage: state.message + " But This Will Not"
  }),
  methods: (state /* infered */, computed /*  inferred wrong */) => {
    return {
      logName: () => console.log(state.message),
      logComputedName: () => console.log(computed.computedMessage) // Does not compile
    };
  }
});
4
  • computed.computedMessage does not exist because computed is a function. Returned value have computedMessage so computed(someStatus).computedMessage should have more sense. But I didn't understand what are you trying to do. Commented Aug 1, 2019 at 9:50
  • @DanieleAlessandra, It is already called the way you've described, I've modified the code to make it more clear. Commented Aug 1, 2019 at 9:59
  • 1
    @Daniel I have been banging my head for the past 45 mins, don't think there is a way to do this without splitting this in multiple parameters, I just can't get the compiler to do contextual typing for the parameters and get the return type C inferred correctly. Might be a limitation in the way these two features work. Maybe someone else has some idea.. Commented Aug 1, 2019 at 11:15
  • 1
    @TitianCernicova-Dragomir. Thanks for the 45 mins, followed you in Twitter :-) I know about the splitted parameter solution. Thanks again. Commented Aug 1, 2019 at 11:20

1 Answer 1

4

I believe this is not possible in the current Typescript version.

I've been experimenting with your code and it seems Type Inference work with some internal priority, which dictates that type should be inferred from parameter when possible, over inference from return value.

If you'll remove the methods parameter from your code, you'll see computed return value - C, will be inferred correctly as:

{ computedMessage: string }

When methods included,C is inferred as unknown, since it is exist as a parameter in methods, so typescript will prefer to try to get the correct type based on methods behavior rather then computed.

Sign up to request clarification or add additional context in comments.

1 Comment

Hi @yuval.bl can you give a link to refer to which line of code in Typescript the priority "should be inferred from parameter when possible, over inference from return value"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.