-
Notifications
You must be signed in to change notification settings - Fork 539
Change Recipes
This is a collection of some patterns that can be used to manage changes that will eventually be or would otherwise be breaking.
Deprecating an API in order to change it to be @internal
may be handled without the internal usages appearing deprecated (requiring no-deprecated
lint disables). Since standard API separation is generated from a single file, a split is required with a re-tagged API to make this work.
- Apply the
@deprecated
tag to the original API. It is important to keep the original tags in place to make it clear that API is externally exposed. - Create a new
internal.ts
source next toindex.ts
that re-exports everything:export * from "./index.js";
. - Add a new named export copying the API. Import original renamed and exported as copy.
- Change package.json export for
/internal
tointernal.*
instead ofindex.*
. - As needed, apply policy required changes. Try
pnpm policy-check:fix
.
Example: PR 23332: Making ContainerRuntime externally deprecated - see files under packages/runtime/container-runtime
Classes and enums are both values and types and the type of (typeof
) the value is not the same as the type. To clone a class or enum fully, both a type and value should be cloned.
packages/runtime/container-runtime/src/internal.ts of PR 23332 avoids @deprecated
for /internal
version of ContainerRuntime
.
import { ContainerRuntime as ContainerRuntimeClass } from "./containerRuntime.js";
export type ContainerRuntime = ContainerRuntimeClass;
export const ContainerRuntime = ContainerRuntimeClass;
There is no known simple way to clone a namespace. To clone a namespace it needs redeclared member by member. So it may be advantageous to only resurface the minimal members when needed. (api-extractor
may insist in a large "internal" namespace be exposed, but for /internal
uses only tiny number of set actually needs surfaced.)
Example: TODO - use jason-ha's pending core-interfaces reorg for Presence infrastructure
Classes exposed outside of a package often lead to undesired maintenance burdens complicating change and evolution. When a class does not have protected members including transitive ones from extends
specification, then a type equivalent interface and new function may be substituted.
- Add replacement exported interface using original class name.
-
extends
the interface by allimplements
specifications. - Copy declaration of all class public members not covered by
extends
(above) into the interface.
-
- Rename the class and extend from the interface.
- Add an exported
const
variable using original class name.- Type as a union of
-
new
function using class constructor's parameters and returning the interface - object declaration containing public static class members
-
- Assign to it the renamed class.
- Type as a union of
- If class had any static members that had original class types and accessed private members, there will need to be a cast (
as
) to renamed class.
Before
export interface A {
value: number;
}
export class B implements A {
public readonly id: string = "instanceOfB";
private readonly shh = 98;
public constructor(public value: number) {}
public static readPrivate(bThis: B): number {
return bThis.shh;
}
}
After
export interface A {
value: number;
}
// Step 1
export interface B extends A {
readonly id: string;
}
// Step 2
class BImpl implements B {
public readonly id = "instanceOfB";
private readonly shh = 98;
public constructor(public value: number) {}
public static readPrivate(bThis: B): number {
return (bThis as BImpl).shh; // Step 4
}
}
// Step 3
export const B: (new (value: number) => B) & {
readPrivate: (bThis: B) => number;
} = BImpl;
This wiki is focused on contributing to the Fluid Framework codebase.
For information on using Fluid Framework or building applications on it, please refer to fluidframework.com.
- Submitting Bugs and Feature Requests
-
Contributing to the Repo
- Repo Basics
- Common Workflows and Patterns
- Managing dependencies
- Client Code
- Server Code
- PR Guidelines
- CI Pipelines
- Breaking vs Non-Breaking Changes
- Branches, Versions, and Releases
- Compatibility & Versioning
- Testing
- Debugging
- npm package scopes
- Maintaining API support levels
- Developer Tooling Maintenance
- API Deprecation
- Working with the Website (fluidframework.com)
- Coding Guidelines
- Documentation Guidelines
- CLA