สืบหาประเภทตามประเภททั่วไปของสมบัติพี่น้องใน Typescript
ฉันต้องการกำหนดประเภทของคุณสมบัติขึ้นอยู่กับประเภททั่วไปของคุณสมบัติที่อยู่ใกล้กัน
ตัวอย่างเช่น สมมติว่าเรามี:
type Person = {
id: number;
name: string;
}
type Select<Value=unknown> = (props:Props<Value>) => any;
const PersonSelect:Select<Person> = (props) => null //implementation is irrelavant
const TextSelect:Select<string> = (props) => null //implementation is irrelavant
แล้วฉันต้องการที่จะสามารถทำอะไรแบบนี้ได้:
type Filter<V = unknown > = {
component: Select<V>,
transformer: (value: V) => string
};
const filters:Array<Filter> = [
{
component: PersonSelect,
transformer: (selected) => selected.name //type of `selected` should be infered as `Person`
},
{
component: TextSelect,
transformer: (selected) => selected // type of `selected` should be infered as `string`
}
]
วิธีแก้ปัญหา
ด้วยโค้ดด้านบนนี้ ฉันสามารถทำมันแบบ
const personFilter:Filter<Person> = {
component: PersonSelect,
transformer: (selected) => selected.name
}
const textFilter:Filter<string> = {
component: TextSelect,
transformer: (selected) => selected
}
const filters = [personFilter, textFilter];
แต่ฉันกำลังมองหาวิธีแก้ปัญหาที่ใช้งานได้โดยไม่ต้องกำหนดชนิดของวัตถุฟิลเตอร์แต่ละตัวอย่างชัดเจน นอกจากนี้ ชนิดทั่วไป V สามารถเป็นอะไรก็ได้ ดังนั้นฉันจึงไม่สามารถใช้การรวมกันของความเป็นไปได้ทั้งหมดได้
มีวิธีแก้ปัญหาที่ดีกว่านี้ไหม?
คำตอบ #1
ดูเหมือนว่า TypeScript จะมีปัญหาในการอนุมานอาร์กิวเมนต์ของฟังก์ชันลูกศรโดยอิงจากคุณสมบัติอื่นของวัตถุเดียวกัน
ฉันไม่สามารถทำมันได้ด้วยความช่วยเหลือของการอนุมานฟังก์ชัน
วิธีที่ง่ายที่สุดคือการสร้างฟังก์ชัน builder ซึ่งส่งกลับ Filter<_>
type Person = {
id: number;
name: string;
}
type Props<T> = T
type Select<Value = unknown> = (props: Props<Value>) => any;
const PersonSelect: Select<Person> = (props) => null //implementation is irrelavant
const TextSelect: Select<string> = (props) => null //implementation is irrelavant
type Filter<V = unknown> = {
component: Select<V>,
transformer: <T extends V>(value: T & V) => string
};
const builder = <V,>(
component: Select<V>,
transformer: (value: V) => string
): Filter<V> =>
({ component, transformer })
const filters = [
builder(PersonSelect, (selected) => selected.name),
builder(TextSelect, (selected) => selected)
]
สนามเด็กเล่น
เพราะอาร์กิวเมนต์ component และ transformer ไม่ใช่ส่วนหนึ่งของโครงสร้างข้อมูลเดียวกัน จึงง่ายกว่าที่จะอนุมานพวกมันและใช้ข้อจำกัดประเภทของเรา
ที่นี่คุณสามารถหาตัวอย่างเพิ่มเติมของการอนุมานชนิดบนอาร์กิวเมนต์ของฟังก์ชันได้
