ST_FUNC開発日記

建築構造設計Excelアドイン開発の記録

断面性能の計算の残りを実装

他の断面性能計算を実装

現状A,mしか計算していなかったので、ほかの数値についても実装した。

結果がNaNのときは非表示

数値を入力する前は結果がNaNになってしまうので非表示にした。

断面の種類を切り替えたときの処理

断面形状を切り替えたときに前の数値が残っていたので、inputboxと結果、描画をリセットするようにした。

断面性能計算に断面二次モーメント、断面係数、断面二次半径の計算を追加 · st-func/st-func-web@14d202d · GitHub

組立角形鋼管の断面形状描画を追加

ビルドボックスについても断面形状の描画を追加した。 四角形を書くだけなので簡単。

組立角形鋼管の断面形状描画を追加 · st-func/st-func-web@588e2de · GitHub

コンソールのエラーメッセージ対応

デバッグしようと思って開発者ツールを開いてみたらエラーメッセージが出ていたので対処する。

キーを持て

Warning: Each child in a list should have a unique "key"

というエラーが。そういえば、サンプルコードとかでもkeyという属性が設定されたりしていたような。

qiita.com

この辺を参考に。

兄弟要素が識別できるようにキーを振ればいいのかな?

inputテーブル

これは固定で4つ並べているだけだから、indexを振ればいいかな。

resultテーブル

こちらは記号ごとに行があるので、symbolをkeyにしてみる。

svg内のLine

線については毎度描画しなおした方がいい気がするので、randomにしてしまう。

lineの属性にNaNを使わないで

NaNがあった場合はLineを作らないような処理を入れる。

これでとりあえずコンソールのエラーは出ないようになった。

コンソールのエラーメッセージ対応 · st-func/st-func-web@18faa02 · GitHub

断面形状の描画 その2

前回作った断面形状描画部分を拡張しやすいように修正していく。

LineData

LineDataに関しては、x1,y1,x2,y2といちいち書いていくといまいちなので、点データをもたせて、それを結ぶ仕組みとした。

また、多角形のデータを1本1本持たせるのは面倒なので、点の配列をもたせるようにした。

描画時に1本ずつに分離するpointPairsメソッドを作成。

...という演算子?があるようだ。あまり使い慣れないが、うまく使えば便利?

Point

LineDataの点情報。実際の座標情報とスクリーン上の座標情報を両方持たせられるようにした。

ビューポート的な感じ?

DrawingData

linesだけではなくて、width,height,scaleみたいな描画に必要な情報を集約することにした。

オフセットできるように原点データも持たせる。

line情報に加えて、lineで使われているpoint情報もリストとして取得するようにした。(addLineで被りがないようにリストに入れる)

これは、スクリーン座標を作る処理などの効率を上げるためである。

setScreenCoordinateでDrawingDataの情報をもとに、Pointのスクリーン座標を設定する。

ViewMatrixみたいな座標変換行列でやるべきなきもするが、そこまで真面目ではないので簡易的なもの。

setAutoScaleはpoint情報をもとに、いい感じに原点とスケールを設定するもの。この辺もPointを別配列にしたので処理がやりやすい。

ここでも...出てきた。...に投げるときは...を使うといいのね。

おわり

これでだいぶスッキリしたかな?

DrawSection.tsxはこんな感じになった。

import React from "react";
import { SecFlatBar } from "@st-func/st-func-ts";

class Point {
  x: number;
  y: number;
  x_screen: number;
  y_screen: number;
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
    this.x_screen = x;
    this.y_screen = y;
  }
}

class LineData {
  points: Point[];
  constructor(...points: Point[]) {
    this.points = points;
  }
  pointPairs(): [Point, Point][] {
    let result: [Point, Point][] = [];
    for (let i = 0; i < this.points.length - 1; i++) {
      result.push([this.points[i], this.points[i + 1]]);
    }
    return result;
  }
}

export class DrawingData {
  points: Point[] = [];
  lines: LineData[] = [];
  scale: number = 1;
  origin: Point = new Point(0, 0);
  width: number = 500;
  height: number = 500;
  addLine(line: LineData): void {
    this.lines.push(line);
    for (let point of line.points) {
      if (!this.points.includes(point)) {
        this.points.push(point);
      }
    }
  }
  setScreenCoordinate(): void {
    for (let point of this.points) {
      point.x_screen =
        this.origin.x_screen + (point.x - this.origin.x) * this.scale;
      point.y_screen =
        this.origin.y_screen + (point.y - this.origin.y) * this.scale;
    }
  }
  setAutoScale(): void {
    if (this.points.length === 0) {
      return;
    }
    let max_x = Math.max(...this.points.map((point) => point.x));
    let min_x = Math.min(...this.points.map((point) => point.x));
    let max_y = Math.max(...this.points.map((point) => point.y));
    let min_y = Math.min(...this.points.map((point) => point.y));
    let dx = max_x - min_x;
    let dy = max_y - min_y;
    this.origin.x = dx / 2;
    this.origin.y = dy / 2;
    this.origin.x_screen = this.width / 2;
    this.origin.y_screen = this.height / 2;
    if (dx === 0 && dy === 0) {
      this.scale = 1;
    } else {
      let scale_x = Number.MAX_SAFE_INTEGER;
      if (dx !== 0) {
        scale_x = (this.width * 0.95) / dx;
      }
      let scale_y = Number.MAX_SAFE_INTEGER;
      if (dy !== 0) {
        scale_y = (this.height * 0.95) / dy;
      }
      this.scale = Math.min(scale_x, scale_y);
    }
  }
}

interface DrawingProps {
  drawingData: DrawingData;
}

export const Drawing: React.FC<DrawingProps> = ({ drawingData }) => {
  drawingData.setScreenCoordinate();
  return (
    <svg width={drawingData.width} height={drawingData.height}>
      {drawingData.lines.map((line) => {
        return line.pointPairs().map(([point1, point2]) => {
          return (
            <line
              x1={point1.x_screen}
              y1={point1.y_screen}
              x2={point2.x_screen}
              y2={point2.y_screen}
              stroke="black"
            />
          );
        });
      })}
    </svg>
  );
};

export function flatBarDrawing(secFlatBar: SecFlatBar): DrawingData {
  const points: Point[] = [];
  points.push(new Point(0, 0));
  points.push(new Point(secFlatBar.t, 0));
  points.push(new Point(secFlatBar.t, secFlatBar.b));
  points.push(new Point(0, secFlatBar.b));
  points.push(points[0]);
  const result: DrawingData = new DrawingData();
  result.addLine(new LineData(...points));
  return result;
}

断面形状の描画機能でスケール自動調整機能などを追加 · st-func/st-func-web@608cc49 · GitHub

断面形状の描画 その1

数値を入力しただけだと地味なので、断面形状を描画できるようにしたい。

さっそくChatGPTに相談してみる。

reactのフロントエンドアプリを作っており、図形を描画したい旨をいろいろ聞いてみたら、下記のようなコードを提案された。

import React, { useState } from 'react';

const LineDrawer = () => {
  const [startX, setStartX] = useState(50);
  const [startY, setStartY] = useState(50);
  const [endX, setEndX] = useState(150);
  const [endY, setEndY] = useState(150);
  const [lines, setLines] = useState([]);

  const addLine = () => {
    const newLines = [
      ...lines,
      { startX, startY, endX, endY, id: Date.now() },
    ];
    setLines(newLines);
  };

  return (
    <div>
      <div>
        <label htmlFor="startX">Start X:</label>
        <input
          type="number"
          id="startX"
          value={startX}
          onChange={(e) => setStartX(Number(e.target.value))}
        />
      </div>
      <div>
        <label htmlFor="startY">Start Y:</label>
        <input
          type="number"
          id="startY"
          value={startY}
          onChange={(e) => setStartY(Number(e.target.value))}
        />
      </div>
      <div>
        <label htmlFor="endX">End X:</label>
        <input
          type="number"
          id="endX"
          value={endX}
          onChange={(e) => setEndX(Number(e.target.value))}
        />
      </div>
      <div>
        <label htmlFor="endY">End Y:</label>
        <input
          type="number"
          id="endY"
          value={endY}
          onChange={(e) => setEndY(Number(e.target.value))}
        />
      </div>
      <button onClick={addLine}>Add Line</button>
      <div style={{ position: 'relative', width: '500px', height: '500px', border: '1px solid black' }}>
        {lines.map(line => (
          <svg key={line.id}>
            <line
              x1={line.startX}
              y1={line.startY}
              x2={line.endX}
              y2={line.endY}
              style={{ stroke: 'black', strokeWidth: 2 }}
            />
          </svg>
        ))}
      </div>
    </div>
  );
};

export default LineDrawer;

なるほど。最初はcanvasか何かを使うのかなと思ったけど、コンポーネントsvgを作ってしまえばいいのか。

念のために聞いてみる。

reactで描画を行おうと思います。canvasを使うのとsvgを使うのどちらのほうが良いですか?

canvasSVGのどちらを使うかは、具体的な描画の内容や目的によって異なります。

  • Canvasは、ピクセル単位で描画を行うため、複雑なグラフィックスやアニメーションを作成するのに適しています。例えば、ゲームや高度なグラフの描画に利用されます。一方で、Canvasは描画された要素を構造化していないため、アクセシビリティSEOには不向きです。

  • SVGベクター形式で描画を行うため、拡大縮小しても画質が劣化しません。また、SVG要素はHTML要素として直接記述できるため、テキストベースの編集やスタイリングが容易です。SVGはアニメーションやグラフィックスを描画する際にも利用されます。SEOアクセシビリティにも配慮しやすいです。

どちらを選択するかは、以下のような点を考慮して決定できます:

  1. 描画内容の複雑さ: 複雑なグラフィックスやアニメーションを行う場合はCanvasが適しています。
  2. 拡大縮小の必要性: 描画物を拡大縮小したい場合はSVGが有利です。
  3. 構造化とスタイリング: HTML要素として構造化して扱いたい場合はSVGが使いやすいです。
  4. アクセシビリティSEO: テキストベースの要素として扱いたい、またはSEOアクセシビリティを重視する場合はSVGが適しています。

どちらを選んでも、ReactではCanvasSVGを簡単に扱うことができますので、プロジェクトの要件に合わせて適切なものを選択してください。

そんな複雑な図形は書かないので、svgでいいかな。

ということで最初のコード例を参考に以下の様に構成してみた。

  1. 線の情報のデータクラスを作る
  2. 線の情報をもとにsvgを描画するコンポーネントを作成
  3. 断面情報から線の情報を作る関数を作成
  4. 断面の計算をするタイミングで線の情報をコンポーネントに渡す

以上をもとに下記のようなコンポーネントを作って、作成してみたところ、無事に断面形状が表示された。

DrawSection.tsx

import React from "react";
import { SecFlatBar } from "@st-func/st-func-ts";
import { Unit } from "@st-func/st-func-ts";
export class LineData {
  x1: number;
  y1: number;
  x2: number;
  y2: number;
  constructor(x1: number, y1: number, x2: number, y2: number) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
  }
}
export interface DrawLinesProps {
  width: number;
  height: number;
  lines: LineData[];
}
export const DrawLines: React.FC<DrawLinesProps> = ({
  width,
  height,
  lines,
}) => {
  return (
    <svg width={width} height={height}>
      {lines.map((line) => {
        return (
          <line
            x1={line.x1}
            y1={line.y1}
            x2={line.x2}
            y2={line.y2}
            stroke="black"
          />
        );
      })}
    </svg>
  );
};

export function flatBarLines(secFlatBar: SecFlatBar): LineData[] {
  const lines: LineData[] = [];
  const t = Unit.output(secFlatBar.t, "mm");
  const b = Unit.output(secFlatBar.b, "mm");
  lines.push(new LineData(0, 0, t, 0));
  lines.push(new LineData(t, 0, t, b));
  lines.push(new LineData(t, b, 0, b));
  lines.push(new LineData(0, b, 0, 0));
  return lines;
}

とりあえず作った感なので、次回はもう少しコードをブラッシュアップしていきたい。

計算結果が一歩遅れるのの解消

数値を更新したらすぐ結果が反映させる仕様にしたが、よく見ると表示結果が1つ前の計算結果だった。

細かい仕組みはしっかり認識していないが、レンダリングと数値更新のタイミングの問題らしい?

CharGPTに相談したら、ボタンで計算させましょうとか、タイムアウトで少し待ちましょうとかやや頓珍漢な答えを出されてしまった。

久々に検索で記事を探すことに。

userEffectを使うとか、いろいろあったけど、なかなかうまくいかず、いろいろ試行錯誤していた結果、一時的に新しい値を変数に入れておくという作戦でうまくいった。

いろいろなサイトを見ながらやったので、どれで解決したのかわからなくなってしまった。

断面性能計算で、ひとつ前の入力の結果が表示されてしまう不具合を修正 · st-func/st-func-web@006c50b · GitHub

試行錯誤をしたために、ちょっとうっとおしいコードになってしまった。

さすがにnewNumとかgetNumとかが大量にあるのは邪魔なので、配列を使って整理。

最初のuserStateの部分もうまくまとめられないかな、と思ったが、逆に複雑になりそうなので、ここは手を付けないでおいた。

断面性能計算の寸法入力部の処理を配列を利用して整理 · st-func/st-func-web@a7a405b · GitHub

WEBアプリの断面性能計算部分の整理

これまでに出てきた技術を見ながら、拡張しやすいように改良してく。

断面形状タイプのenumを作成

断面形状の切り替えに文字列リテラルのユニオンを使っていたが、

モードの数が増えてくるとユニオンをいちいち書くのが面倒なので、enum型を使うことにした。

enum型はst-func-tsのほうに入れた。

断面形状タイプのenumを作成 · st-func/st-func-ts@c54cdf7 · GitHub

断面切り替えに断面形状タイプのenumを利用 · st-func/st-func-web@8bafe74 · GitHub

断面寸法入力部分のコンポーネント

断面寸法入力部分がif文でちょっと汚い書き方だったので、結果表示部分と同様コンポーネント化してみる。

必要なデータと、setNumなどもinterfaceに含めて、コンポーネントに受け渡してみる。

受け渡すための配列は、jsonオブジェクトをそのまま作ると属性名をいちいち書くのが面倒なので、タプルの配列を作り、それをmapでオブジェクトにした。

断面性能計算の寸法入力欄をコンポーネント化 · st-func/st-func-web@0da56e2 · GitHub

計算を即時反映するようにする

たいして負荷のかかる計算ではないので、計算ボタンを押さなくても結果が表示されるようにした。

断面性能計算で計算ボタンを押さなくても即時計算するように修正 · st-func/st-func-web@8524f58 · GitHub

入力欄の変換を関数化

いちいちfloat変換、単位変換を書くのが面倒なので、num1~4を取得するgetNum関数を作り、スッキリかけるように修正。

断面性能計算で入力欄の変換部分を関数化 · st-func/st-func-web@35cece5 · GitHub

数値書式の調整

floatで、ゴミが入ると桁数がすごく多くなってしまうのでいい感じにしたい。

桁数を絞るのはtoFixedという関数でできるみたいだが、整数値の時に.000とか表示されるとあまりうれしくない。

ということでChatGPTに相談

C#の.tostring("0.###")のようなことをtypescriptでできますか?

はい、TypeScriptでも同様のフォーマットを実現することができます。例えば、小数点以下3桁までのフォーマットを行う場合は、次のようにします。

const number = 123.456789;
const formattedNumber = number.toFixed(3); // "123.457"

このコードでは、toFixed() メソッドを使用して小数点以下の桁数を指定しています。3桁まで表示するために .toFixed(3) としていますが、これを任意の桁数に変更することもできます。

もし特定の桁数までの表示を行う場合で、余分な0を表示しないようにしたい場合は、少しトリッキーですが次のようにします。

const number = 123.4;
const formattedNumber = Number(number.toFixed(3)).toString(); // "123.4"

ここでは、toFixed() で指定した桁数までの数値を取得し、それを Number() で数値に変換してから .toString() を使って文字列に変換しています。これにより、余分な0を表示しないフォーマットを実現できます。

ChatGPTが少しトリッキーとか言っているのが面白いけど、これで実現できそうなので採用。

断面性能計算の計算結果の表示桁数を設定できるように修正 · st-func/st-func-web@0d3ffe0 · GitHub

WEBアプリで他の断面性能も計算する仕組みを作る

ファイル名の修正他

とりあえずCalculatorのままだといまいちなので、ファイル名やコンポーネント名などを修正

断面性能計算のクラス名を修正 · st-func/st-func-web@d164fcd · GitHub

ほかの断面性能

現在断面積の結果しか表示されないが、ほかの断面性能も計算していきたい。

最初に考えたのは

const [area, setArea] = useState<number | undefined>(undefined);
const [massPerMetre, setMassPerMetre] = useState<number | undefined>(undefined);

というように大量に変数を作って処理してみようと思ったのだが、ちょっと書くのがめんどそうである。

そこで、

const [result, setResult] = useState<string | undefined>(undefined);

というのを作って、そこに結果のhtmlを書き込んでしまえばいいのではないかということにした。

結果部分はひたすらテキストで書いていくとちょっと見にくそうなので、表にしてしまいたい。

ということは、コンポーネントを使えばいいに違いない。

ということでChatGPTさんに相談

reactでfor分でtableのtrを作っていくにはどう書けばよいですか?

分は文のたいぽ。

javascriptのコードになってしまったので

言語はtypescriptです

を追記。

TypeScriptを使用して同じ動作を実現する場合は、コンポーネントのpropsやstateにデータを保持し、それを利用して動的にtableを生成することができます。以下はその例です。

import React from 'react';

interface User {
  id: number;
  name: string;
  age: number;
}

interface Props {
  data: User[];
}

const UserTable: React.FC<Props> = ({ data }) => (
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Age</th>
      </tr>
    </thead>
    <tbody>
      {data.map((user) => (
        <tr key={user.id}>
          <td>{user.id}</td>
          <td>{user.name}</td>
          <td>{user.age}</td>
        </tr>
      ))}
    </tbody>
  </table>
);

export default UserTable;

このコンポーネントはUser型の配列を受け取り、そのデータを元に動的にtableのtr要素を生成します。map関数を使ってデータ配列を走査し、各要素に対してtr要素を生成しています。また、キー(key)属性を設定してReactに一意性を伝えています。これを利用する側では、適切なデータをpropsとして渡すことでこのコンポーネントを利用できます。

ということで、上記を参考に断面性能計算結果の表を作る。

interface CalcData {
  secPropertyType: SecPropertyType;
  symbol: string;
  description: string;
  unit: string;
  result: number | undefined;
}

interface CalcDataProps {
  calcDatas: CalcData[];
}
const ResultTable: React.FC<CalcDataProps> = ({ calcDatas }) => (
  <table>
    <tbody>
      {calcDatas.map((calcData) => (
        <tr>
          <td>{calcData.description}</td>
          <td>{calcData.symbol}</td>
          <td>=</td>
          <td>
            {calcData.result}
            {calcData.unit}
          </td>
        </tr>
      ))}
    </tbody>
  </table>
);

このコンポーネントを使ってresultにhtmlをセットしようと思ったのだけど、なかなかうまくいかなかった。

ということで、コンポーネントではなく、CalcDataの配列のみを渡すことにした。

なんやかやで、こんな感じに。

import React, { useState } from "react";
import {
  SecBuildBox,
  SecFlatBar,
  SecPropertyType,
  SecSteel,
} from "@st-func/st-func-ts";
import { Unit } from "@st-func/st-func-ts";

interface CalcData {
  secPropertyType: SecPropertyType;
  symbol: string;
  description: string;
  unit: string;
  result: number | undefined;
}

interface CalcDataProps {
  calcDatas: CalcData[];
}
const ResultTable: React.FC<CalcDataProps> = ({ calcDatas }) => (
  <table>
    <tbody>
      {calcDatas.map((calcData) => (
        <tr>
          <td>{calcData.description}</td>
          <td>{calcData.symbol}</td>
          <td>=</td>
          <td>
            {calcData.result}
            {calcData.unit}
          </td>
        </tr>
      ))}
    </tbody>
  </table>
);

const SecProperty: React.FC = () => {
  const [calcMode, setCalcMode] = useState<"buildBox" | "flatBar">("flatBar");
  const [num1, setNum1] = useState("");
  const [num2, setNum2] = useState("");
  const [num3, setNum3] = useState("");
  const [num4, setNum4] = useState("");
  const [result, setResult] = useState<CalcData[] | undefined>(undefined);

  const handleCalculation = () => {
    let secSteel: SecSteel;
    if (calcMode === "buildBox") {
      const secBuildBox: SecBuildBox = new SecBuildBox();
      secBuildBox.setDimensions(
        Unit.input(parseFloat(num1), "mm"),
        Unit.input(parseFloat(num2), "mm"),
        Unit.input(parseFloat(num3), "mm"),
        Unit.input(parseFloat(num4), "mm")
      );
      secSteel = secBuildBox;
    } else if (calcMode === "flatBar") {
      const secFlatBar: SecFlatBar = new SecFlatBar();
      secFlatBar.setDimensions(
        Unit.input(parseFloat(num1), "mm"),
        Unit.input(parseFloat(num2), "mm")
      );
      secSteel = secFlatBar;
    } else {
      secSteel = new SecSteel();
    }
    let calcDatas: CalcData[] = [
      {
        secPropertyType: SecPropertyType.Area,
        symbol: "A",
        description: "断面積",
        unit: "mm^2",
        result: undefined,
      },
      {
        secPropertyType: SecPropertyType.MassPerMetre,
        symbol: "m",
        description: "単位質量",
        unit: "kg/m",
        result: undefined,
      },
    ];
    for (let calcData of calcDatas) {
      calcData.result = Unit.output(
        secSteel.property(calcData.secPropertyType),
        calcData.unit
      );
    }
    setResult(calcDatas);
  };

  return (
    <div>
      <h2>断面性能計算</h2>
      <h3>断面寸法</h3>
      <div>
        <label>断面タイプ:</label>
        <select
          value={calcMode}
          onChange={(e) =>
            setCalcMode(e.target.value as "buildBox" | "flatBar")
          }
        >
          <option value="buildBox">組立角形鋼管(BuildBox)</option>
          <option value="flatBar">平鋼(FlatBar)</option>
        </select>
      </div>
      <div>
        <label>Number 1:</label>
        <input
          type="number"
          value={num1}
          onChange={(e) => setNum1(e.target.value)}
        />
      </div>
      <div>
        <label>Number 2:</label>
        <input
          type="number"
          value={num2}
          onChange={(e) => setNum2(e.target.value)}
        />
      </div>
      {calcMode === "buildBox" && (
        <div>
          <div>
            <label>Number 3:</label>
            <input
              type="number"
              value={num3}
              onChange={(e) => setNum3(e.target.value)}
            />
          </div>
          <div>
            <label>Number 4:</label>
            <input
              type="number"
              value={num4}
              onChange={(e) => setNum4(e.target.value)}
            />
          </div>
        </div>
      )}
      <button onClick={handleCalculation}>計算</button>
      <div>
        <h3>計算結果</h3>
        {result !== undefined ? (
          <ResultTable calcDatas={result} />
        ) : (
          "寸法を入力してください"
        )}
      </div>
    </div>
  );
};

export default SecProperty;

ここで、コードはあっていそうだけど下記のようなエラーが出ている。

Cannot access ambient const enums when 'isolatedModules' is enabled.

インポートはできているのに何でエラーになるのかな? ということでChatGPTに相談。

/**
 * 断面性能のタイプ
 */
export const enum SecPropertyType {
  Area = "断面積",
  ElasticModulusX = "断面係数X",
  ElasticModulusY = "断面係数Y",
  MassPerMetre = "単位質量",
  RadiusOfGyrationX = "断面二次半径X",
  RadiusOfGyrationY = "断面二次半径Y",
  SecondMomentOfAreaX = "断面二次モーメントX",
  SecondMomentOfAreaY = "断面二次モーメントY",
}

これをnpmでインストールしてほかのパッケージで呼び出したところ
Cannot access ambient const enums when 'isolatedModules' is enabled.
というエラーが出ました。なぜでしょうか。

このエラーは、TypeScriptでisolatedModulesオプションを有効にしている場合に、環境でambient const enums を利用できないことが原因です。isolatedModulesオプションは、各ファイルを個別にコンパイルするためのものであり、ambient const enums は型情報のみを生成するため、コードが生成されません。そのため、isolatedModulesオプションとambient const enumsを同時に使うことはできません。

このエラーを解決するためには、次のいずれかの方法を選択することができます。

  1. isolatedModulesオプションを無効にする。
  2. enumをconst enumではなく通常のenumに変更する。
  3. enumを外部モジュールとして定義して、それをインポートする。

具体的な対応方法を教えてもらえると、どの方法が適切か判断できますか?

2はどうすればよいのですか?

enumを通常のenumに変更するためには、constキーワードを取り除くだけです。つまり、以下のようにenumを修正します。

/**
 * 断面性能のタイプ
 */
export enum SecPropertyType {
  Area = "断面積",
  ElasticModulusX = "断面係数X",
  ElasticModulusY = "断面係数Y",
  MassPerMetre = "単位質量",
  RadiusOfGyrationX = "断面二次半径X",
  RadiusOfGyrationY = "断面二次半径Y",
  SecondMomentOfAreaX = "断面二次モーメントX",
  SecondMomentOfAreaY = "断面二次モーメントY",
}

これにより、ambient const enums を使用しなくなり、isolatedModulesオプションが有効な状態でもエラーが発生しなくなります。

なるほど。constを付けたせいでエラーになっていたのかな? でも、なんかenumjavascriptの互換性からconstつけた方がいいとどっかの記事で見たような・・・。といってもtypescriptでやっている以上使い勝手が悪いので、constは消すことにした。

SecPropertyTypeをconst enumから通常のenumへ修正 · st-func/st-func-ts@1f2fb24 · GitHub

これでうまく動いた!

断面性能計算に単位質量を追加 · st-func/st-func-web@8fb1837 · GitHub