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

สืบหาประเภทตามประเภททั่วไปของสมบัติพี่น้องใน 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 ไม่ใช่ส่วนหนึ่งของโครงสร้างข้อมูลเดียวกัน จึงง่ายกว่าที่จะอนุมานพวกมันและใช้ข้อจำกัดประเภทของเรา

ที่นี่คุณสามารถหาตัวอย่างเพิ่มเติมของการอนุมานชนิดบนอาร์กิวเมนต์ของฟังก์ชันได้