Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Typescript: Extracting type of value from a types.map(ModelType) in a generic function drops actions and views from returned type#2153

Answeredbythegedge
evelant asked this question inGeneral
Discussion options

Bug report

  • [X ] I've checked documentation and searched for existing issues
  • [X ] I've made sure my project is based on the latest MST version
  • [X ] Forkthis code sandbox or another minimal reproduction.

Sandbox link or minimal reproduction code
https://codesandbox.io/s/withered-wind-ks771?file=/src/App.tsx

Describe the expected behavior
Given the following function

export function filterMapValues<K, V>(m: Map<K, V>, predicate: (v: V) => any): V[] {    const res: V[] = []    for (const [k, v] of m) {        if (!!predicate(v)) {            res.push(v)        }    }    return res}

With the following input

const firstModel = t.model({}).views((self) => ({  get foo(): string {    return "foo";  }}));const secondModel = t.model({  myMap: t.map(firstModel)});const m = secondModel.create({ myMap: { test: {} } });//Expect this to return [m]const f = filterMapValues(m.myMap, (val) => val.foo === "foo");

Describe the observed behavior

Property 'foo' does not exist on type 'ExtractCSTWithSTN<IModelType<{}, { readonly foo: string; }, _NotCustomized, _NotCustomized>>'.
Property 'foo' does not exist on type 'ModelCreationType<ExtractCFromProps<{}>>'.ts(2339

// Can't access the view "foo" on valconst f = filterMapValues(m.myMap, (val) => val.foo === "foo");
You must be logged in to vote

So the major issue here is thatIMSTMap<IT extends IAnyType> isalmost aMap<string | number, IT["Type"]>, but not quite because of this one method:

set(key: string | number, value: ExtractCSTWithSTN<IT>): this

If we changevalue toIT["type"] you'll find TS infers the right thing forK andV. In its current form, I'm guessingV gets inferred asExtractCSTWithSTN<IT> | IT["Type"] which is the same asExtractCSTWithSTN<IT>.

That leads to the next problem: since this is a view,IT["CreationType"] obviously doesn't have that property (only the props!).

That sums up the problem. I'll think about if there's a solution or not, but I'm highly doubtful.

In the meantime, swap outMap<K, V> forIt…

Replies: 9 comments

Comment options

Hey@evelant - thanks for putting together this issue. I'm sorry it's taken so long for us to get back to you.

TypeScript inference is a known problem with MST, and it's definitely something we're trying to improve. That said, I don't have a great fix for you right now off the top of my head.

If you found a solution to this, it would help a lot for others to see it. If you didn't and moved past it, no worries at all.

For now, I'm going to mark this as a TypeScript issue, label it that help is welcome, and hopefully we can find a path forward to make this kind of thing easier.

You must be logged in to vote
0 replies
Comment options

More info/perhaps related - TypeScript seems to have trouble inferring things about nested models intypes.map overall.

In this CodeSandbox, TypeScript complains about thetodoStore types, even though they should be satisfactory.

But in this CodeSandbox, TS is happy with us fortypes.array

You must be logged in to vote
0 replies
Comment options

An example a little closer to the original problem:https://codesandbox.io/s/clever-margulis-ks8fx7?file=/src/App.tsx.types.array is working here.

You must be logged in to vote
0 replies
Comment options

Ooh, butarray.filter method is typed withany, so maybe if we write a customfilter method this would break, too. I have to hop off for a while but I'd be curious if anyone else looks into that to see if this is just an issue with the generics overall.

You must be logged in to vote
0 replies
Comment options

I will check tomorrow

You must be logged in to vote
0 replies
Comment options

I have looked into the map implementation, there are few places withany tried fixing them, but still couldn't find the root where the types are getting changed

You must be logged in to vote
0 replies
Comment options

Thanks@chakrihacker! We can keep this open and maybe revisit it over time. Lots of TypeScript work to be done, haha!

You must be logged in to vote
0 replies
Comment options

So the major issue here is thatIMSTMap<IT extends IAnyType> isalmost aMap<string | number, IT["Type"]>, but not quite because of this one method:

set(key: string | number, value: ExtractCSTWithSTN<IT>): this

If we changevalue toIT["type"] you'll find TS infers the right thing forK andV. In its current form, I'm guessingV gets inferred asExtractCSTWithSTN<IT> | IT["Type"] which is the same asExtractCSTWithSTN<IT>.

That leads to the next problem: since this is a view,IT["CreationType"] obviously doesn't have that property (only the props!).

That sums up the problem. I'll think about if there's a solution or not, but I'm highly doubtful.

In the meantime, swap outMap<K, V> forIterable<[K, V]> and all your problems go away! In general, I would highly recommend doing this. Not everyone is super intoSOLID, but I've always found the "I" to be invaluable to great design, especially in a type system that's very structural. I like to think about it as "ask only for what you need".

You must be logged in to vote
0 replies
Answer selected bycoolsoftwaretyler
Comment options

Thanks@thegedge - this is an excellent solution. Really appreciate your insight.

I'm going to convert this issue to a discussion, which will close it. I forked the original reproduction and made theIterable change, and thing are working over here:https://codesandbox.io/p/sandbox/inspiring-neco-5t5dsq

Here's the code for posterity:

import"./styles.css";import{typesast}from"mobx-state-tree";/** * Like array.filter except on a map, returns value[] array of found results *@param m *@param predicate *@returns */exportfunctionfilterMapValues<K,V>(m:Iterable<[K,V]>,predicate:(v:V)=>any):V[]{constres:V[]=[];for(const[k,v]ofm){if(!!predicate(v)){res.push(v);}}returnres;}constfirstModel=t.model({}).views((self)=>({getfoo():string{return"foo";},}));constsecondModel=t.model({myMap:t.map(firstModel),});constm=secondModel.create({myMap:{test:{}}});//Views don't exist when extracting the value type of//an instance from a map in a generic function.//Instead we seem to get only the props.constf=filterMapValues(m.myMap,(val)=>val.foo==="foo");exportdefaultfunctionApp(){return<divclassName="App"></div>;}
You must be logged in to vote
0 replies
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Labels
help/PR welcomeHelp/Pull request from contributors to fix the issue is welcomeTypescriptIssue related to Typescript typings
4 participants
@evelant@thegedge@chakrihacker@coolsoftwaretyler
Converted from issue

This discussion was converted from issue #1775 on February 26, 2024 01:01.


[8]ページ先頭

©2009-2025 Movatter.jp