Skip to main content

實例分享

實例分享 (一)

export const sendEmail = async (payload: IMailPayload, file: File): Promise<any> => {
const formData = new FormData();
for (const key in payload) {
formData.append(key, payload[key]); // 👈 這裡會有問題
}
};

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IMailPayload'. No index signature with a parameter of type 'string' was found on type 'IMailPayload'.ts(7053)

針對 payload[key] 部分,有幾種改進的方法:

  1. 使用 Object.entries() 方法:

    const formData = new FormData();
    Object.entries(payload).forEach(([key, value]) => {
    formData.append(key, value);
    });

    這種方式可以直接遍歷 payload 對象的鍵值對,並將它們添加到 FormData 中。

  2. 使用 for...in 迭代器,並對 key 進行類型安全檢查:

    const formData = new FormData();
    for (const key in payload) {
    if (Object.prototype.hasOwnProperty.call(payload, key)) {
    formData.append(key, payload[key]);
    }
    }

    這種方式可以確保只對 payload 對象自身的屬性進行迭代,而不包括原型鏈上的屬性。

  3. 如果你確定 payload 是一個純對象(non-prototype-based),可以使用 Object.keys() 方法:

    const formData = new FormData();
    Object.keys(payload).forEach((key) => {
    formData.append(key, payload[key]);
    });

    這種方式更簡單,但要確保 payload 不會有來自原型鏈的屬性。

  4. 使用 for...of 迭代器和 Object.entries():

    const formData = new FormData();
    for (const [key, value] of Object.entries(payload)) {
    formData.append(key, value);
    }

    這種方式結合了前面提到的方法,提供了更好的類型安全性和可讀性。

選擇哪種方式取決於您的具體需求和 payload 對象的結構。如果您確定 payload 是一個純對象,第三種方式可能是最簡單的。如果您不確定 payload 的結構,第四種方式可能是最安全的選擇。

實例分享(二)

在 TypeScript 中,要表達 互斥的邏輯(mutually exclusive types),通常使用的是 聯合類型(union types) 搭配 discriminated union(判別聯合)條件類型與 never 搭配排除不合法的組合

以下是兩種常見的寫法:

✅ 方法一:使用 discriminated union(最常見)

這種方式會使用一個「判別字段」(如 type)來區分類型。

type A = {
type: "a";
aProp: string;
bProp?: never; // 禁止出現 bProp
};

type B = {
type: "b";
bProp: number;
aProp?: never; // 禁止出現 aProp
};

type AB = A | B;

// 用法示例
const example1: AB = {
type: "a",
aProp: "hello",
};

const example2: AB = {
type: "b",
bProp: 123,
};

// 錯誤示例(aProp 與 bProp 不應同時存在)
// const invalid: AB = {
// type: 'a',
// aProp: 'hello',
// bProp: 123, // ❌ bProp 不應出現
// };

✅ 方法二:排除非法組合(進階寫法)

這種方式可以用在沒有 discriminator 字段的情況下,例如:

type OnlyA = { a: string; b?: never };
type OnlyB = { a?: never; b: number };

type AorB = OnlyA | OnlyB;

// 正確:
const val1: AorB = { a: "hello" };
const val2: AorB = { b: 42 };

// 錯誤(互斥邏輯)
// const val3: AorB = { a: 'hello', b: 42 }; // ❌ 會錯

延伸:多個選項互斥的情況

你可以利用 工具類型 來動態建立互斥關係(例如在表單選項中只允許其中一個出現):

type XOR<T, U> = (T & { [K in keyof U]?: never }) | (U & { [K in keyof T]?: never });

type A = { a: string };
type B = { b: number };

type AorB = XOR<A, B>;

const good1: AorB = { a: "foo" };
const good2: AorB = { b: 123 };
// const bad: AorB = { a: 'foo', b: 123 }; // ❌