Ideas for Arc XP

Provide full TypeScript support and official TypeScript declarations for Fusion Engine.

After inquiring about TypeScript support within Fusion Engine, it was confirmed that TypeScript declarations are not currently provided, and there is no official roadmap for their inclusion. Therefore, I suggest that Fusion Engine incorporates full TypeScript support, including official TypeScript declarations. This feature would streamline development processes, improve type-checking, and enhance overall developer experience, particularly for those of us transitioning from JavaScript to TypeScript. It would also align with modern web development practices and the growing adoption of TypeScript across the industry. In our project, we are exploring the transition from JavaScript to TypeScript, and Fusion Engine is a core part of our architecture. Adding official TypeScript declarations would greatly reduce friction in this transition. It would enable us to catch errors earlier during development, improve the scalability of our codebase, and enhance collaboration across our team through clear and consistent type definitions. Additionally, better tooling and editor integration would speed up development and reduce the need for custom type declarations. Ultimately, this feature would support a more robust and maintainable codebase while also appealing to new Fusion Engine users who already rely on TypeScript.
  • Julio Quintana
  • Oct 11 2024
  • Future consideration
  • Attach files
  • JP Blanchette commented
    13 Feb 22:34

    For the typings/fusion/prop-types.d.ts file content, see: https://ideas.arcxp.com/ideas/PEN-I-42

  • JP Blanchette commented
    13 Feb 22:33

    These files are compatible with FUSION_RELEASE=6.0.1 and probably v7 too.

    File typings/fusion/consumer.ts

    declare module "fusion:consumer" {
    // This is the best I could do for now.
    export default function Consumer<C>(Component: C): C;
    }

    File typings/fusion/content.ts

    declare module "fusion:content" {
    export function useContent<C = any, Q = object>(config: {
    source: string;
    query?: Q;
    filter?: string;
    transform?: (data: object) => any;
    inherit?: boolean;
    staticMode?: boolean;
    }): C;

    export function useEditableContent(): {
    editableField: (fieldProp: string) => {
    "data-feature": string;
    "data-field-editable": string;
    contentEditable: "true";
    };

    editableContent: (
    contentObj: object,
    contentProp: object | string
    ) => {
    "data-feature": string;
    "data-content-editable": string;
    contentEditable: "true";
    };

    searchableField: (
    fieldProp: string,
    type?: string
    ) => {
    "data-feature": string;
    "data-field-editable": string;
    contentEditable: "true";
    "data-searchable": "true";
    "data-searchable-type": string;
    };

    searchableContent: (
    contentObj: object,
    contentProp: object | string,
    type?: string
    ) => {
    "data-feature": string;
    "data-content-editable": string;
    contentEditable: "true";
    "data-searchable": "true";
    "data-searchable-type": string;
    };
    };
    }

    File: typings/fusion/context.ts

    // Page Metadata from PB Editor
    declare global {
    type MetaValue = (name: string) => string | undefined;
    }

    // Fusion Context doc:
    // https://docs.arcxp.com/alc/en/context-component-api?sys_kb_id=06a1471687393d50637f315d0ebb35cf&id=kb_article_view
    declare module "fusion:context" {
    // The application context is globally scoped and includes properties that apply to the entire rendered page.
    type appContext = {
    arcSite: string;
    contentCache: Record<
    string,
    Record<string, { data: any; expires: number; lastModified: number }>
    >;
    contextPath: string;
    deployment: (resourcePath: string) => string;
    globalContent: any;
    globalContentConfig: any;
    metaValue: MetaValue;
    isAdmin: boolean;
    layout: string;
    outputType: string;
    renderables: any[];
    // Warning: requestUri may differ when accessed client-side vs server-side.
    // Server-side: Excludes all URL query parameters and excludes the hash fragment.
    // Client-side: Includes all URL query parameters and excludes the hash fragment.
    requestUri: string;
    siteProperties: any;
    template: string;
    tree: any;
    };

    // The component context includes properties that apply to the closest ancestor component.
    // Which would be the closest Layout, Chain, or Feature/Block component.
    type componentContext = {
    collection: string;
    type: string;
    id: string;
    name: string;
    customFields: any;
    displayProperties: any;
    globalContent: any;
    registerSuccessEvent: any;
    };

    // The Fusion context contains an extra property
    type fusionContext = {
    segmentID: string | null; // Audience Targeting Segment ID (null when no variant pages configured for page)
    };

    export default function FusionContext(): appContext;

    export function AppContext(): appContext;
    export function ComponentContext(): componentContext;
    export function FusionContext(): appContext & componentContext & fusionContext;

    export function useAppContext(): appContext;
    export function useComponentContext(): componentContext;
    export function useFusionContext(): appContext & componentContext & fusionContext;

    export function withAppContext(): appContext;
    export function withComponentContext(): componentContext;
    export function withFusionContext(): appContext & componentContext & fusionContext;
    }

    File typings/fusion/layout.ts

    declare module "fusion:layout";

    declare global {
    // For: const { renderables } = useAppContext();
    type FusionRenderable<T> = {
    collection: string;
    type: string;
    props?: { customFields: T };
    children?: any[];
    };
    }

    File typings/fusion/properties.ts

    declare global {
    // Align type with actual file: /properties/index.js
    type SiteProperties = {
    pie: string;
    pizza: {
    hut: number;
    };
    };
    }
    declare module "fusion:properties" {
    export default function getProperties(site: string): SiteProperties;
    }

    File typings/fusion/quarantine.ts

    declare module "fusion:quarantine"; // I don't use this module.

    File typings/fusion/unpack.ts

    declare module "fusion:unpack"; // I don't use this module.

    File typings/fusion/staic.ts

    import type { ReactElement } from "react";

    declare module "fusion:static" {
    type StaticProps = {
    id: string;
    htmlOnly?: boolean;
    persistent?: boolean;
    children: any;
    };

    function Static(props: StaticProps): ReactElement;
    }

    export default Static;

    File tsconfig.json

    {
    "compilerOptions": {
    "allowJs": true,
    "baseUrl": ".",
    "checkJs": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "incremental": true,
    "isolatedModules": true,
    "jsx": "react",
    "lib": ["dom", "dom.iterable", "es2021"],
    "module": "commonjs",
    "moduleDetection": "force",
    "noEmit": true,
    "paths": {
    "~/*": ["./*"],
    "fusion:*": ["./typings/fusion/*.ts"]
    },
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "target": "es2021"
    },
    "exclude": [
    "tsconfig.json",
    "node_modules",
    ],
    "include": [
    "components/**/*",
    "content/**/*",
    "environment/*",
    "properties/**/*",
    "scripts/**/*",
    "src/**/*",
    "typings/**/*.ts",
    ],
    "typeAcquisition": {
    "enable": true
    }
    }
  • Admin
    Fatih Yildiz commented
    October 14, 2024 12:47

    Thanks for submitting this idea Julio. Typescript support is in our minds and we'd like to provide type definitions for fusion exports (or imports for you) that would provide better in-IDE experience.