- 
                Notifications
    
You must be signed in to change notification settings  - Fork 557
 
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 
@deprecatedtag 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.tssource next toindex.tsthat 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 
/internaltointernal.*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 an essentially type equivalent interface and new function may be substituted.
Warning The replacement
interfacewill not provide exact type checking protections that the originalclassafforded. If the class was not already@sealed, then understand if any customer may have had reason to inherit the class.
- Add replacement exported interface using original class name.
- 
extendsthe interface by allimplementsspecifications. - Copy declaration of all class public members not covered by 
extends(above) into the interface. - Be sure the interface is 
@sealedeven if original class was not. 
 - 
 - Rename the class and extend from the interface.
 - Add an exported 
constvariable using original class name.- Type as a union of
- 
newfunction 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
/** @sealed */
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