Skip to content

Commit 49ccf38

Browse files
Move get onto ReadOnlyReactive per RFC review
No new public CachedValue type: get() joins the ReadOnlyReactive interface (an RFC 1071 oversight) and both cachedValue() and the cached() overload return ReadOnlyReactive<Value>. The CachedValue class stays as an internal implementation detail. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent ea6ee0e commit 49ccf38

6 files changed

Lines changed: 19 additions & 12 deletions

File tree

packages/@ember/-internals/metal/lib/cached.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
// of @cached, so any changes made to one should also be made to the other
44
import { assert } from '@ember/debug';
55
import { DEBUG } from '@glimmer/env';
6-
import { type CachedValue, cachedValue } from '@glimmer/validator/lib/cached-value';
6+
import { cachedValue } from '@glimmer/validator/lib/cached-value';
7+
import type { ReadOnlyReactive } from '@glimmer/validator/lib/tracked-value';
78
import { createCache, getValue } from '@glimmer/validator/lib/tracking';
89

910
/**
@@ -142,16 +143,19 @@ export function cached<T>(
142143
* `cached` as a standalone cached reactive value, usable outside of classes:
143144
* `const doubled = cached(() => count.value * 2)`.
144145
*/
145-
export function cached<Value>(fn: () => Value, options?: CachedValueOptions): CachedValue<Value>;
146-
export function cached(...args: any[]): CachedValue<unknown> | void {
146+
export function cached<Value>(
147+
fn: () => Value,
148+
options?: CachedValueOptions
149+
): ReadOnlyReactive<Value>;
150+
export function cached(...args: any[]): ReadOnlyReactive<unknown> | void {
147151
const [target, key, descriptor] = args;
148152

149153
// Error on `@cached()`, `@cached(...args)`, and `@cached propName = value;`
150154
if (DEBUG && target === undefined) throwCachedExtraneousParens();
151155

152156
if (typeof target === 'function' && args.length <= 2) {
153157
/*
154-
Standalone form. Returns a read-only `CachedValue` usable outside of
158+
Standalone form. Returns a `ReadOnlyReactive` usable outside of
155159
classes. A legacy decorator invocation always receives three arguments,
156160
so it can never land in this branch.
157161

packages/@glimmer/tracking/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export type {
66
ReadOnlyReactive,
77
TrackedValue,
88
} from '@glimmer/validator/lib/tracked-value';
9-
export type { CachedValue } from '@glimmer/validator/lib/cached-value';
109

1110
/**
1211
In order to tell Ember a value might change, we need to mark it as trackable.

packages/@glimmer/validator/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ if (Reflect.has(globalThis, GLIMMER_VALIDATOR_REGISTRATION)) {
88

99
Reflect.set(globalThis, GLIMMER_VALIDATOR_REGISTRATION, true);
1010

11-
export { CachedValue, cachedValue } from './lib/cached-value';
11+
export { cachedValue } from './lib/cached-value';
1212
export { trackedArray } from './lib/collections/array';
1313
export { trackedMap } from './lib/collections/map';
1414
export { trackedObject } from './lib/collections/object';

packages/@glimmer/validator/lib/cached-value.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { type Cache, createCache, getValue } from './tracking';
99
* re-invokes the wrapped function when tracked state it previously read has
1010
* changed.
1111
*/
12-
export class CachedValue<Value = unknown> implements ReadOnlyReactive<Value> {
12+
class CachedValue<Value = unknown> implements ReadOnlyReactive<Value> {
1313
readonly #cache: Cache<Value>;
1414

1515
constructor(fn: () => Value, options?: { description?: string }) {
@@ -35,6 +35,6 @@ export class CachedValue<Value = unknown> implements ReadOnlyReactive<Value> {
3535
export function cachedValue<Value>(
3636
fn: () => Value,
3737
options?: { description?: string }
38-
): CachedValue<Value> {
38+
): ReadOnlyReactive<Value> {
3939
return new CachedValue(fn, options);
4040
}

packages/@glimmer/validator/lib/tracked-value.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ export interface Reactive<Value> {
2020
*/
2121
export interface ReadOnlyReactive<Value> extends Reactive<Value> {
2222
readonly value: Value;
23+
24+
/**
25+
* Function short-hand for reading `value`.
26+
*/
27+
get: () => Value;
2328
}
2429

2530
export class TrackedValue<Value = unknown> implements Reactive<Value> {

type-tests/@glimmer/tracking-test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { cached, tracked } from '@glimmer/tracking';
2-
import type { CachedValue, Reactive, ReadOnlyReactive, TrackedValue } from '@glimmer/tracking';
2+
import type { Reactive, ReadOnlyReactive, TrackedValue } from '@glimmer/tracking';
33
import { expectTypeOf } from 'expect-type';
44

55
// ------- public types -------
@@ -53,12 +53,11 @@ expectTypeOf(tracked({ value: 'Zoey' }, {})).toMatchTypeOf<Reactive<Record<strin
5353
// ------- cached: standalone form -------
5454
const doubled = cached(() => count.value * 2);
5555

56-
expectTypeOf(doubled).toMatchTypeOf<ReadOnlyReactive<number>>();
57-
expectTypeOf(doubled).toMatchTypeOf<CachedValue<number>>();
56+
expectTypeOf(doubled).toEqualTypeOf<ReadOnlyReactive<number>>();
5857
expectTypeOf(doubled.value).toEqualTypeOf<number>();
5958
expectTypeOf(doubled.get()).toEqualTypeOf<number>();
6059

61-
// @ts-expect-error -- a CachedValue is read-only
60+
// @ts-expect-error -- the returned value is read-only
6261
doubled.value = 4;
6362

6463
// ------- cached: standalone form with options -------

0 commit comments

Comments
 (0)