Improve TypeScript types and error handling
- Created proper TypeScript types for Office API operations - Replaced 'any' casts with appropriate types - Added type-safe utility functions in office-types.ts - Improved error handling with proper unknown type - Added helper functions for PowerPoint shape operations - Created proper TypeScript interface for webpack HMR These changes improve code quality, maintainability, and help catch potential bugs at compile time rather than runtime. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import * as React from "react";
|
||||
import { Button, ButtonProps } from "@fluentui/react-components";
|
||||
import { useStatusContext } from "./App";
|
||||
import { useCommonStyles } from "./commonStyles";
|
||||
import { getErrorMessage } from "../types/office-types";
|
||||
|
||||
export interface ActionButtonProps {
|
||||
icon: ButtonProps["icon"];
|
||||
@@ -37,8 +38,8 @@ export const ActionButton: React.FC<ActionButtonProps> = ({
|
||||
setIsProcessing(true);
|
||||
try {
|
||||
await onClick();
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = getErrorMessage(error);
|
||||
setStatusMessage(`Error: ${errorMessage}`);
|
||||
setStatusType("error");
|
||||
console.error(`Error in ${title} action:`, error);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from "@fluentui/react-icons";
|
||||
import { useStatusContext } from "./App";
|
||||
import { useCommonStyles } from "./commonStyles";
|
||||
import { getErrorMessage, isPictureShape, getFirstSelectedSlide, selectShapesById } from "../types/office-types";
|
||||
|
||||
export const RoundImage: React.FC = () => {
|
||||
const styles = useCommonStyles();
|
||||
@@ -38,8 +39,8 @@ export const RoundImage: React.FC = () => {
|
||||
shape.load(["type"]);
|
||||
await context.sync();
|
||||
|
||||
// Ensure the shape is a picture
|
||||
if (shape.type !== PowerPoint.ShapeType.image) {
|
||||
// Ensure the shape is a picture using our type-safe utility
|
||||
if (!isPictureShape(shape)) {
|
||||
setStatusMessage("Please select an image.");
|
||||
setStatusType("warning");
|
||||
return;
|
||||
@@ -53,8 +54,10 @@ export const RoundImage: React.FC = () => {
|
||||
const width = shape.width;
|
||||
const height = shape.height;
|
||||
|
||||
const slide = context.presentation.getSelectedSlides().getItemAt(0);
|
||||
const maskShape = slide.shapes.addGeometricShape("Ellipse" as any);
|
||||
// Get the current slide using our type-safe utility
|
||||
const slide = getFirstSelectedSlide(context);
|
||||
// Create elliptical mask with proper type
|
||||
const maskShape = slide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.ellipse);
|
||||
|
||||
maskShape.load(["width", "height", "left", "top", "id"]);
|
||||
await context.sync();
|
||||
@@ -73,17 +76,19 @@ export const RoundImage: React.FC = () => {
|
||||
setStatusMessage("Created mask shape. Please select both the image and the oval, then use the 'Shape Forma > Merge Shapes > Intersect' command in PowerPoint.");
|
||||
setStatusType("warning");
|
||||
|
||||
slide.setSelectedShapes([shape.id, maskShape.id]);
|
||||
// Use our type-safe utility for selecting shapes
|
||||
selectShapesById(slide, [shape.id, maskShape.id]);
|
||||
// Ensure we maintain the same size
|
||||
shape.width = width;
|
||||
shape.height = height;
|
||||
|
||||
await context.sync();
|
||||
});
|
||||
} catch (error) {
|
||||
setStatusMessage(`Error: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = getErrorMessage(error);
|
||||
setStatusMessage(`Error: ${errorMessage}`);
|
||||
setStatusType("error");
|
||||
console.error("Main error:", error);
|
||||
console.error("Round image error:", error);
|
||||
} finally {
|
||||
setIsProcessing(false);
|
||||
}
|
||||
|
||||
+15
-3
@@ -19,9 +19,21 @@ Office.onReady(() => {
|
||||
);
|
||||
});
|
||||
|
||||
if ((module as any).hot) {
|
||||
(module as any).hot.accept("./components/App", () => {
|
||||
// Define proper module hot interface for webpack hot module replacement
|
||||
interface HotModule extends NodeModule {
|
||||
hot?: {
|
||||
accept(path: string, callback: () => void): void;
|
||||
};
|
||||
}
|
||||
|
||||
// Use the proper type for module with HMR
|
||||
if ((module as HotModule).hot) {
|
||||
(module as HotModule).hot?.accept("./components/App", () => {
|
||||
const NextApp = require("./components/App").default;
|
||||
root?.render(NextApp);
|
||||
root?.render(
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
<NextApp title={title} />
|
||||
</FluentProvider>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Type definitions for the Office JS API
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extended Error interface for Office/PowerPoint API errors
|
||||
*/
|
||||
export interface OfficeApiError extends Error {
|
||||
code?: string;
|
||||
debugInfo?: {
|
||||
code?: string;
|
||||
message?: string;
|
||||
errorLocation?: string;
|
||||
statement?: string;
|
||||
innerError?: any;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to safely extract error message from any error object
|
||||
*/
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for PowerPoint API operations on shapes
|
||||
*/
|
||||
export function isPictureShape(shape: PowerPoint.Shape): boolean {
|
||||
return shape.type === PowerPoint.ShapeType.image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for working with PowerPoint slides
|
||||
*/
|
||||
export function getFirstSelectedSlide(context: PowerPoint.RequestContext): PowerPoint.Slide {
|
||||
return context.presentation.getSelectedSlides().getItemAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe utility for selecting shapes
|
||||
*/
|
||||
export function selectShapesById(slide: PowerPoint.Slide, shapeIds: string[]): void {
|
||||
slide.setSelectedShapes(shapeIds);
|
||||
}
|
||||
Reference in New Issue
Block a user