typescript - จำกัดคุณสมบัติของอ็อบเจ็กต์ให้เป็น keyof ของอินเทอร์เฟซ
โค้ดนี้จะคอมไพล์ไม่ได้:
interface IFoo {
a: number;
}
type TFoo = keyof IFoo;
type OFoo = { [key: TFoo]: any };
let obj: OFoo = { a: 1 };
สิ่งที่ฉันพยายามทำให้สำเร็จคือการให้ obj สามารถกำหนดค่าได้เฉพาะกับวัตถุที่มีคุณสมบัติที่ถูกต้องเท่านั้น เหมือนกับว่าฉันเขียนว่า:
let obj: IFoo = { a: 1};
แต่ฉันต้องทำมันด้วย keyof
ขอบคุณสำหรับไอเดียใดๆ
คำตอบ #1
แม้ว่าคุณจะไม่สามารถใช้สิ่งใดนอกจาก string หรือ number เป็นประเภทคีย์ในลายเซ็นดัชนีโดยตรง (และคำจำกัดความของคุณสำหรับ OFoo จะทำให้เกิดข้อผิดพลาดในลักษณะนั้น) คุณ สามารถ จำกัดคีย์ให้เป็นชนิดย่อยของ string โดยใช้ mapped types เนื่องจาก TFoo หรือที่เรียกว่า keyof Foo เป็นชนิดย่อยของ string คุณจึงสามารถใช้ mapped type แบบนี้:
type OFoo = { [K in TFoo]: any };
สังเกตว่าสัณฐานวิธีสำหรับ mapped types จะแตกต่างจากสัณฐานวิธีของ index signatures ปกติ TFoo ข้างต้นสอดคล้องกับประเภทของคีย์ที่อนุญาต ซึ่งในกรณีของคุณคือ "a" เพียงอย่างเดียว แต่ก็อาจเป็น union ของ string literals เช่น "a"|"b"|"c" หรือแม้แต่ string และ K ข้างต้นเป็นพารามิเตอร์ที่สอดคล้องกับ type ของคีย์สำหรับแต่ละ property (คุณไม่ต้องสนใจ K จริงๆ เพราะประเภทของ value ของแต่ละ property คือ any และไม่เกี่ยวข้องกับ K แต่คุณอาจใช้ K เพื่อเลือก property พิเศษบางอย่างได้ถ้าต้องการ) อย่างไรก็ตาม ลองใช้มัน:
let obj: OFoo = { a: 1 }; // okay
let obj = { }; // error, property 'a' is missing
let obj = { c: 1 }; // error, excess property 'c'
อย่างไรก็ตาม ผมคงจะใช้ประเภทไลบรารีมาตรฐานที่มีอยู่ในตัว Record<K,T> ซึ่งถูกกำหนดไว้ดังนี้:
type Record<K extends string, T> = {
[P in K]: T
}
หรือคุณสามารถคิดว่า: "Record<K, T> คืออ็อบเจ็กต์ที่ทุกคีย์อยู่ใน K และทุกค่าเป็น T" และสำหรับคุณ K คือ TFoo และ T คือ any:
type OFoo = Record<TFoo, any>; // same thing
หวังว่านั่นจะช่วยได้ โชคดีนะ!
