ค้นหาเว็บไซต์

TypeScript - กำหนดประเภทของคลาสและอาร์กิวเมนต์ของคอนสตรัคเตอร์โดยให้ซ้ำซ้อนน้อยที่สุด


ฉันมีคลาสแบบนี้อยู่ตอนนี้:

class Person {
    id?: string = uuid();
    name: string;

    constructor(data: Person) {
        _.merge(this, data);
    }
}

โดยที่ 'uuid' เป็นฟังก์ชันที่สร้างรหัส และ '_' เป็น lodash

ปัญหาของฉันคือฉันมีฟังก์ชันที่ต้องการ id: function savePersonInDb(p: Person & { id: string }) {...} และ TypeScript จึงไม่ยอมให้เรียกใช้งานกับ new Person() เพราะว่า id เป็นค่าเลือก แต่จริง ๆ แล้วมันจะถูกสร้างขึ้นทุกครั้งเมื่อเรียก constructor

ฉันรู้ว่าฉันสามารถทำบางอย่างแบบ:

interface PersonData {
    id?: string;
    name: string;
}

class Person {
    id: string = uuid();
    name: string;

    constructor(data: PersonData) {
        _.merge(this, data);
    }
}

แต่ฉันไม่ค่อยชอบความคิดที่จะต้องเขียนคุณสมบัติทั้งหมดสองครั้ง คุณเห็นทางไหนที่ฉันจะทำสิ่งที่ต้องการได้ง่ายกว่านี้ไหม?

โอ้ แล้วฉันลืมบอกไป แต่ในโปรเจกต์จริงของฉันฉันมีมากกว่า 2 แอตทริบิวต์ ดังนั้นฉันจะซาบซึ้งมากถ้าไม่ต้องเขียนมันซ้ำสองครั้งสำหรับทุกคลาส

ขอบคุณสำหรับความช่วยเหลือของคุณ!

คำตอบ #1

แล้วถ้าใช้ Omit เพื่อสร้างชนิดจาก Person ที่เอาการกำหนดชนิดทั้งหมดยกเว้น 'id' ซึ่งถูกทำให้เป็นทางเลือก (playground):

type OptionalId<T> = {
    id?: string
} & Omit<T, 'id'>

// PersonData is automatically updated when Person is changed
type PersonData = OptionalId<Person>;

// savePersonInDb just takes Person
function savePersonInDb(person: Person) {}

class Person {
    id: string = ''; // uuid();
    name: string = '';
    member1: number = 0;
    // member2 and so on

    constructor(data: PersonData) {
        // _.merge(this, data);
    }
}

// id is optional
const person = new Person({
    name: 'test',
    member1: 5
});

// new person object can be used.
savePersonInDb(person)