Skip to content

Commit 1a58812

Browse files
committed
feat: forwardRef parameter better typings
1 parent 9d0284b commit 1a58812

File tree

6 files changed

+200
-89
lines changed

6 files changed

+200
-89
lines changed

.changeset/fluffy-beans-spend.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"mobx-view-model": minor
3+
---
4+
5+
better typings support of `forwardedRef` prop and `ref` prop handling

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
},
5858
"dependencies": {
5959
"react-simple-loadable": "^2.3.9",
60-
"yummies": "^5.11.1"
60+
"yummies": "^5.12.0"
6161
},
6262
"peerDependencies": {
6363
"mobx": "^6.12.4",
@@ -83,7 +83,7 @@
8383
"sborshik": "^1.0.33",
8484
"vite": "^7.1.10",
8585
"tsx": "^4.20.5",
86-
"typescript": "^5.9.2",
86+
"typescript": "^5.9.3",
8787
"vitest": "^3.1.2"
8888
},
8989
"packageManager": "[email protected]+sha512.140036830124618d624a2187b50d04289d5a087f326c9edfc0ccd733d76c4f52c3a313d4fc148794a2a9d81553016004e6742e8cf850670268a7387fc220c903"

pnpm-lock.yaml

Lines changed: 40 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hoc/with-lazy-view-model.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { type PackedAsyncModule, unpackAsyncModule } from 'yummies/imports';
77
import type { Class, Maybe, MaybePromise } from 'yummies/utils/types';
88
import { viewModelsConfig } from '../config/index.js';
99
import type { AnyViewModel, AnyViewModelSimple } from '../view-model/index.js';
10-
1110
import {
1211
type ViewModelHocConfig,
1312
type ViewModelSimpleHocConfig,

src/hoc/with-view-model.test.tsx

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,7 +1609,32 @@ describe('withViewModel', () => {
16091609
});
16101610

16111611
describe('typings', () => {
1612-
it('1', async () => {
1612+
it('simple no props declaration (model prop infer type)', async () => {
1613+
class ParentMemeVM extends ViewModelBase {
1614+
kek = 1;
1615+
}
1616+
class MemeVM extends ViewModelBase<EmptyObject, ParentMemeVM> {
1617+
pek = this.parentViewModel?.kek;
1618+
1619+
getFoo() {
1620+
return '1';
1621+
}
1622+
}
1623+
1624+
const Meme = withViewModel(MemeVM, ({ model }) => {
1625+
expectTypeOf(model).toEqualTypeOf<MemeVM>();
1626+
return <div>{`hello ${model.pek} ${model.getFoo()}`}</div>;
1627+
});
1628+
1629+
const TestApp = () => {
1630+
return <Meme />;
1631+
};
1632+
1633+
const screen = await act(async () => render(<TestApp />));
1634+
expect(screen.getByText('hello undefined 1')).toBeDefined();
1635+
});
1636+
1637+
it('forwarding refs', async () => {
16131638
type JediType = 'defender' | 'guard' | 'consul';
16141639

16151640
class JediVM<TJediType extends JediType> extends ViewModelBase<{
@@ -1666,7 +1691,7 @@ describe('withViewModel', () => {
16661691

16671692
await act(async () => render(<TestApp />));
16681693
});
1669-
it('forwardedRef already defined (overrided) in ComponentProps', async () => {
1694+
it('forwardedRef already defined (overrided) in ComponentProps (number)', async () => {
16701695
class YourVM extends ViewModelBase {}
16711696

16721697
interface ComponentProps
@@ -1686,8 +1711,82 @@ describe('withViewModel', () => {
16861711
return <Component forwardedRef={1} />;
16871712
};
16881713

1689-
await act(async () => render(<TestApp />));
1714+
const screen = await act(async () => render(<TestApp />));
16901715
expect(screen.getByText('hello 1')).toBeDefined();
16911716
});
1717+
it('forwardedRef already defined (overrided) in ComponentProps (number | undefined) (no prop passed)', async () => {
1718+
class YourVM extends ViewModelBase {}
1719+
1720+
interface ComponentProps
1721+
extends Omit<ViewModelProps<YourVM>, 'forwardedRef'> {
1722+
forwardedRef?: number;
1723+
}
1724+
1725+
const Component = withViewModel(
1726+
YourVM,
1727+
({ forwardedRef }: ComponentProps) => {
1728+
expectTypeOf(forwardedRef).toEqualTypeOf<number | undefined>();
1729+
return <div>{`hello ${forwardedRef}`}</div>;
1730+
},
1731+
);
1732+
1733+
const TestApp = () => {
1734+
return <Component />;
1735+
};
1736+
1737+
const screen = await act(async () => render(<TestApp />));
1738+
expect(screen.getByText('hello undefined')).toBeDefined();
1739+
});
1740+
it('forwardedRef already defined (overrided) in ComponentProps (number | undefined) (prop passed)', async () => {
1741+
class YourVM extends ViewModelBase {}
1742+
1743+
interface ComponentProps
1744+
extends Omit<ViewModelProps<YourVM>, 'forwardedRef'> {
1745+
forwardedRef?: number;
1746+
}
1747+
1748+
const Component = withViewModel(
1749+
YourVM,
1750+
({ forwardedRef }: ComponentProps) => {
1751+
expectTypeOf(forwardedRef).toEqualTypeOf<number | undefined>();
1752+
return <div>{`hello ${forwardedRef}`}</div>;
1753+
},
1754+
);
1755+
1756+
const TestApp = () => {
1757+
return <Component forwardedRef={666} />;
1758+
};
1759+
1760+
const screen = await act(async () => render(<TestApp />));
1761+
expect(screen.getByText('hello 666')).toBeDefined();
1762+
});
1763+
it('ref already defined in ComponentProps', async () => {
1764+
class YourVM extends ViewModelBase {}
1765+
1766+
interface ComponentProps extends ViewModelProps<YourVM> {
1767+
ref?: React.LegacyRef<number>;
1768+
}
1769+
1770+
const Component = withViewModel<YourVM, ComponentProps>(
1771+
YourVM,
1772+
({ forwardedRef }) => {
1773+
expectTypeOf(forwardedRef).toEqualTypeOf<
1774+
React.ForwardedRef<number> | undefined
1775+
>();
1776+
return <div>hello</div>;
1777+
},
1778+
{
1779+
forwardRef: true,
1780+
},
1781+
);
1782+
1783+
const TestApp = () => {
1784+
const ref = useRef(1);
1785+
return <Component ref={ref} />;
1786+
};
1787+
1788+
const screen = await act(async () => render(<TestApp />));
1789+
expect(screen.getByText('hello')).toBeDefined();
1790+
});
16921791
});
16931792
});

0 commit comments

Comments
 (0)