Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .changeset/lazy-lies-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@fluidframework/core-interfaces": minor
"@fluidframework/map": minor
"__section": legacy
---

Add legacy beta map compatibility interfaces

New legacy beta map interfaces make it possible to type legacy map-like DDS APIs against Fluid's stable map abstraction while preserving compatibility with JavaScript `Map` consumers.

Check warning on line 9 in .changeset/lazy-lies-enjoy.md

View workflow job for this annotation

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Microsoft.Acronyms] 'DDS' has no definition. Raw Output: {"message": "[Microsoft.Acronyms] 'DDS' has no definition.", "location": {"path": ".changeset/lazy-lies-enjoy.md", "range": {"start": {"line": 9, "column": 73}}}, "severity": "INFO"}

```typescript
import type { FluidMapLegacy } from "@fluidframework/core-interfaces/legacy";
import type { IDirectoryBeta, ISharedMapBeta } from "@fluidframework/map/legacy";

declare const directory: IDirectoryBeta;
declare const sharedMap: ISharedMapBeta;

const directoryMap: FluidMapLegacy<string, unknown> = directory;
const sharedMapAsMap: Map<string, unknown> = sharedMap;
```
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ export interface FluidMap<K, V> extends FluidReadonlyMap<K, V> {
set(key: K, value: V): void;
}

// @beta @sealed @legacy
export interface FluidMapLegacy<K, V> extends FluidMap<K, V> {
clear(): void;
delete(key: K): boolean;
forEach(callbackfn: (value: V, key: K, map: FluidMapLegacy<K, V>) => void, thisArg?: any): void;
set(key: K, value: V): this;
}

// @public
export type FluidObject<T = unknown> = {
[P in FluidObjectProviderKeys<T>]?: T[P];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ export interface FluidMap<K, V> extends FluidReadonlyMap<K, V> {
set(key: K, value: V): void;
}

// @beta @sealed @legacy
export interface FluidMapLegacy<K, V> extends FluidMap<K, V> {
clear(): void;
delete(key: K): boolean;
forEach(callbackfn: (value: V, key: K, map: FluidMapLegacy<K, V>) => void, thisArg?: any): void;
set(key: K, value: V): this;
}

// @public
export type FluidObject<T = unknown> = {
[P in FluidObjectProviderKeys<T>]?: T[P];
Expand Down
41 changes: 41 additions & 0 deletions packages/common/core-interfaces/src/fluidMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,44 @@ export interface FluidMap<K, V> extends FluidReadonlyMap<K, V> {
*/
set(key: K, value: V): void;
}

/**
* Like TypeScript's built in `Map` type, while still extending {@link FluidMap}.
*
* @privateRemarks
* This interface exists for legacy APIs which were already exposed as built-in `Map`-like types.
* New APIs should prefer {@link FluidMap} unless they need to preserve compatibility with an existing `Map` contract.
*
* @sealed @legacy @beta
*/
export interface FluidMapLegacy<K, V> extends FluidMap<K, V> {
/**
* Removes all entries from the map.
*/
clear(): void;

/**
* Executes the provided function once per each key/value pair in the map.
*/
forEach(
callbackfn: (value: V, key: K, map: FluidMapLegacy<K, V>) => void,
// Typing inherited from Map.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
thisArg?: any,
): void;

/**
* Removes the specified element from the map by its key.
*
* @returns `true` if an element existed and has been removed, or `false` if the element does not exist.
*/
delete(key: K): boolean;

/**
* Adds a new element with a specified key and value to the map.
* If an element with the same key already exists, the element will be updated.
*
* @returns The map itself.
*/
set(key: K, value: V): this;
}
1 change: 1 addition & 0 deletions packages/common/core-interfaces/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type {
FluidIterable,
FluidIterableIterator,
FluidMap,
FluidMapLegacy,
FluidReadonlyMap,
} from "./fluidMap.js";

Expand Down
21 changes: 21 additions & 0 deletions packages/common/core-interfaces/src/test/types/fluidMapTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
FluidIterable,
FluidIterableIterator,
FluidMap,
FluidMapLegacy,
FluidReadonlyMap,
} from "../../index.js";

Expand All @@ -26,6 +27,26 @@ declare type _fluidMap_to_fluidReadonlyMap = requireTrue<
isAssignableTo<FluidMap<string, number>, FluidReadonlyMap<string, number>>
>;

// FluidMapLegacy extends FluidMap while preserving legacy Map-like mutator returns.
declare type _fluidMapLegacy_to_fluidMap = requireTrue<
isAssignableTo<FluidMapLegacy<string, number>, FluidMap<string, number>>
>;
declare type _fluidMapLegacy_to_map = requireTrue<
isAssignableTo<FluidMapLegacy<string, number>, Map<string, number>>
>;
declare type _map_to_fluidMapLegacy = requireTrue<
isAssignableTo<Map<string, number>, FluidMapLegacy<string, number>>
>;

interface LegacyStringMapLike extends Map<string, unknown> {
get<T = unknown>(key: string): T | undefined;
set<T = unknown>(key: string, value: T): this;
}

declare type _legacyStringMapLike_to_fluidMapLegacy = requireTrue<
isAssignableTo<LegacyStringMapLike, FluidMapLegacy<string, unknown>>
>;

// FluidReadonlyMap is assignable to ReadonlyMap (the extra Symbol.toStringTag is compatible).
declare type _fluidReadonlyMap_to_readonlyMap = requireTrue<
isAssignableTo<FluidReadonlyMap<string, number>, ReadonlyMap<string, number>>
Expand Down
12 changes: 12 additions & 0 deletions packages/dds/map/api-report/map.legacy.beta.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export interface IDirectory extends Map<string, any>, IEventProvider<IDirectoryE
subdirectories(): IterableIterator<[string, IDirectory]>;
}

// @beta @sealed @legacy
export interface IDirectoryBeta extends Omit<IDirectory, keyof Map<string, any>>, FluidMapLegacy<string, any> {
get<T = any>(key: string): T | undefined;
set<T = unknown>(key: string, value: T): this;
}

// @beta @deprecated @legacy
export interface IDirectoryDataObject {
ci?: ICreateInfo;
Expand Down Expand Up @@ -91,6 +97,12 @@ export interface ISharedMap extends ISharedObject<ISharedMapEvents>, Map<string,
set<T = unknown>(key: string, value: T): this;
}

// @beta @sealed @legacy
export interface ISharedMapBeta extends Omit<ISharedMap, keyof Map<string, any>>, FluidMapLegacy<string, any> {
get<T = any>(key: string): T | undefined;
set<T = unknown>(key: string, value: T): this;
}

// @beta @sealed @legacy
export interface ISharedMapEvents extends ISharedObjectEvents {
(event: "valueChanged", listener: (changed: IValueChanged, local: boolean, target: IEventThisPlaceHolder) => void): any;
Expand Down
2 changes: 2 additions & 0 deletions packages/dds/map/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@

export type {
IDirectory,
IDirectoryBeta,
IDirectoryEvents,
IDirectoryValueChanged,
ISharedDirectory,
ISharedDirectoryEvents,
ISharedMap,
ISharedMapBeta,
ISharedMapEvents,
IValueChanged,
} from "./interfaces.js";
Expand Down
31 changes: 28 additions & 3 deletions packages/dds/map/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
IEventProvider,
IEventThisPlaceHolder,
} from "@fluidframework/core-interfaces";
import type { FluidMapLegacy } from "@fluidframework/core-interfaces/internal";
import type {
ISharedObject,
ISharedObjectEvents,
Expand Down Expand Up @@ -119,6 +120,17 @@ export interface IDirectory
getWorkingDirectory(relativePath: string): IDirectory | undefined;
}

/**
* Beta version of {@link IDirectory} which uses {@link @fluidframework/core-interfaces/internal#FluidMapLegacy} for its map-like API.
*
* @sealed
* @legacy @beta
*/
export interface IDirectoryBeta
extends Omit<IDirectory, Exclude<keyof Map<string, unknown>, "get" | "set">>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Omit<FluidMapLegacy<string, any>, "get" | "set"> {}

/**
* Events emitted in response to changes to the directory data.
*
Expand Down Expand Up @@ -378,9 +390,11 @@ export interface ISharedMapEvents extends ISharedObjectEvents {
* @sealed
* @legacy @beta
*/
// TODO: Use `unknown` instead (breaking change).
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface ISharedMap extends ISharedObject<ISharedMapEvents>, Map<string, any> {
export interface ISharedMap
// TODO: Use `unknown` instead (breaking change).
extends ISharedObject<ISharedMapEvents>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Map<string, any> {
/**
* Retrieves the given key from the map if it exists.
* @param key - Key to retrieve from
Expand All @@ -398,3 +412,14 @@ export interface ISharedMap extends ISharedObject<ISharedMapEvents>, Map<string,
*/
set<T = unknown>(key: string, value: T): this;
}

/**
* Beta version of {@link ISharedMap} which uses {@link @fluidframework/core-interfaces#FluidMapLegacy} for its map-like API.
*
* @sealed
* @legacy @beta
*/
export interface ISharedMapBeta
extends Omit<ISharedMap, Exclude<keyof Map<string, unknown>, "get" | "set">>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Omit<FluidMapLegacy<string, any>, "get" | "set"> {}
38 changes: 38 additions & 0 deletions packages/dds/map/src/test/types/fluidMapLegacyTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/

import type { requireAssignableTo } from "@fluidframework/build-tools";
import type { FluidMapLegacy } from "@fluidframework/core-interfaces/legacy";

import type { IDirectory, IDirectoryBeta, ISharedMap, ISharedMapBeta } from "../../index.js";

declare type _iDirectoryBeta_to_fluidMapLegacy = requireAssignableTo<
IDirectoryBeta,
FluidMapLegacy<string, unknown>
>;
declare type _iSharedMapBeta_to_fluidMapLegacy = requireAssignableTo<
ISharedMapBeta,
FluidMapLegacy<string, unknown>
>;
declare type _iDirectory_to_map = requireAssignableTo<
IDirectory,
// TODO: Use `unknown` instead (breaking change).
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Map<string, any>
>;
declare type _iSharedMap_to_map = requireAssignableTo<
ISharedMap,
// TODO: Use `unknown` instead (breaking change).
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Map<string, any>
>;
declare type _iDirectoryBeta_to_map = requireAssignableTo<
IDirectoryBeta,
Map<string, unknown>
>;
declare type _iSharedMapBeta_to_map = requireAssignableTo<
ISharedMapBeta,
Map<string, unknown>
>;
Loading