Spark
Spark

Reputation: 86

How to Type a function that receives a function as a parameter with spread arguments?

I'm trying to figure out how to correctly type the parameter applySnapshotFn which is a function that will always take the arguments snapshot and spread ...args.

const applyCssSnapshotFn = (snapshot, cssFileName) => {};
const applyJsSnapshotFn = (snapshot, jsFileName, currentVersion) => {};

const upgradeSnapshot = (
  snapshots: SnapshotType,
  applySnapshotFn: () => void, // How do I properly type this to accept ({snapshot, ...args})?
  args: Record<string, string | boolean>
) => {
  snapshots.map(({ snapshot }) => {
    if (snapshot) {
      applySnapshotFn({ snapshot, ...args });
    }
  });
};

// Calling the function
upgradeSnapshot(snapshots, applyCssSnapshotFn, {
  cssFileName,
});

upgradeSnapshot(snapshots, applyJsSnapshotFn, {
  jsFileName,
  currentVersion,
});

TypeScript playground link for better example

Upvotes: 1

Views: 64

Answers (1)

Adrien De Peretti
Adrien De Peretti

Reputation: 3672

I've updated your code on the playground to propose you a solution

type Snapshot = Record<string, string>;

type SnapshotType = {
    version: string;
    snapshot: Snapshot[];
}

interface UpgradeCssSnapshotArgs {
    cssFileName: string;
};

interface UpgradeJsSnapshotArgs {
    jsFileName: string; 
    currentVersion: string;
};

type SnapshoFnType<T extends UpgradeCssSnapshotArgs | UpgradeJsSnapshotArgs> = (params: { snapshot: Snapshot[]; } & T) => void; 

const snapshots: SnapshotType[] = [{
    version: '0.2',
    snapshot: [
        {
            description: 'Description of action',
            action: 'actions to perform'
        }
    ]
}];

const applyCssSnapshotFn = (params: { snapshot: Snapshot[] } & UpgradeCssSnapshotArgs) => { 
    console.log(params);
};
const applyJsSnapshotFn = (params: { snapshot: Snapshot[] } & UpgradeJsSnapshotArgs) => { 
    console.log(params);
};

const upgradeSnapshot = <T extends UpgradeCssSnapshotArgs | UpgradeJsSnapshotArgs, >(
    snapshots: SnapshotType[],
    applySnapshotFn: SnapshoFnType<T>,
    args: T
) => {
    snapshots.map(({ snapshot }) => {
        if (snapshot) {
            const params = { snapshot, ...args };
            applySnapshotFn(params);
        }
    });
};

// Calling the function
upgradeSnapshot(snapshots, applyCssSnapshotFn, {
    cssFileName: 'Theme.css'
});

upgradeSnapshot(snapshots, applyJsSnapshotFn, {
    jsFileName: 'Home.js',
    currentVersion: '0.1',
});

Playground Link

Upvotes: 1

Related Questions