question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incorrect typescript type when using a function to generate Models with generic types

See original GitHub issue

(duplicate of https://github.com/ctrlplusb/easy-peasy/issues/189, but it seems to have broken again)

I am trying to make a model factory function to generate simple models with just a value and a setter action, where the value is of a generic type. When doing this the action’s state isn’t correctly typed.

example:

import { Action, action } from "easy-peasy";

interface SimpleModel<T> {
  value: T;
  set: Action<SimpleModel<T>, T>;
}

function makeSimpleModel<T>(initialValue: T): SimpleModel<T> {
  return {
    value: initialValue,
    set: action((state, payload) => {
      state.value = payload;
    })
  };
}

…and heres a quick code sandbox https://codesandbox.io/s/sparkling-cookies-4tx0m (doesn’t do anything functional, just to demonstrate the red squiggly)

This generates a compiler error:

Property 'value' does not exist on type '_Merge<StateMapper<_Pick<_Pick<ListModel<T>, ({ 1: never; 0: "value"; }[Extends<T, ActionTypes>] & "value") | ({ 1: never; 0: "value"; }[Extends<T, ActionTypes>] & "set") | ({ 1: never; 0: "value"; }[Extends<...>] & "add") | ({ ...; }[Extends<...>] & "remove")>, (Exclude<...> & ... 1 more ... & "value") | ... 14 mor...'.ts(2339)

easy-peasy version: 3.0.2 (most recent) typescript version: 3.5.3 (most recent)

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
ctrlplusbcommented, Oct 1, 2019

@williammetcalf this is a difficult case as the issue is that T could be an Action or any other type that our statemapper tries to strip out of your model definition when resolving the type for the state argument.

A workaround is to introduce a simple “tuple” type wrapper for T. This basically forces TypeScript to know that the value will never be one of the types it wants to filter, as it is boxed in a valid state type.

For example…

type Value<T> = [T];

interface SimpleModel<T> {
  thevalue: Value<T>;
  theset: Action<SimpleModel<T>, T>;
}

const makeSimpleModel = <T>(initialValue: T): SimpleModel<T> => {
  return {
    thevalue: [initialValue],
    theset: action((state, payload) => {
      state.thevalue = [payload];
    }),
  };
};

Not ideal, as you have to unbox it when using it, but at least TypeScript would be warning you of this.

1reaction
ctrlplusbcommented, Sep 11, 2019

@pirix-gh it is indeed. I haven’t had time to apply the alternative strategy you proposed. 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

How To Use Generics in TypeScript - DigitalOcean
TypeScript fully supports generics as a way to introduce type-safety into components that accept arguments and return values whose type will be ...
Read more >
TypeScript: How to make generic type to infer inside a function?
One of the few places TypeScript does an attempt to model dependent types is when looking up an object property type from a...
Read more >
Documentation - Do's and Don'ts - TypeScript
WRONG */. function reverse(s: String): String;. ✓ Do use the types number , string ... Don't ever have a generic type which doesn't...
Read more >
The true power of TypeScript generics | by Tar Viturawong
Now an attempt to create a type ChangeRecord<object> will fail. Debugging generic type-check. Let's test out our shiny generic types. const ...
Read more >
Keeping Your TypeScript Code DRY With Generics
This way the function is reusable for a different use case but also checks to make sure the type specified is returned. The...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found