reactjs - İç içe geçmiş nesne özellikleri için Typescript jenerik tipi
Bunun gibi bir şeyi başarmak istiyorum, böylece Component türü çıkarılabilir ve props otomatik olarak güvenli bir şekilde türlenebilir.
type ComponentsType<T extends React.FC<any>> {
[key: string]: {
Component: T;
props?: React.ComponentProps<T>
};
}
const components: ComponentsType = {
RedButton: {
Component: Button,
props: { // <- this should be automatically typed to take props of Button
color: 'red'
}
},
BlueButton: {
Component: Button,
props: { // <- this should be automatically typed to take props of Button
color: 'blue'
}
},
FullWidthCard: {
Component: Card,
props: { // <- this should be automatically typed to take props of Card
variant: 'full-width'
}
},
}
Ama yukarıdaki yazım çalışmayacak çünkü generic kısmı nesnenin kökünde yani components'te, her bir özellikte yani RedButton veya FullWidthCard'da değil.
Peki, TypeScript'in bunların üzerinden teker teker geçip Component'i teker teker türetebileceği bir yol var mı?
Teşekkürler
Cevap #1
Beklenen davranışı elde etmek için, her bileşeni ve özellikleri fonksiyon argümanlarından çıkarmanız gerekir. Yani, ekstra bir fonksiyon oluşturmanız gerekir.
import React, { FC, ComponentProps } from 'react'
const Button: FC<{ color: string }> = (props) => null
const Card: FC<{ variant: string }> = (props) => null
type WithProps<T> =
T extends Record<infer Key, infer _> ? {
[P in Key]: T[Key] extends { Component: infer Comp, props: infer PassedProps }
? Comp extends React.JSXElementConstructor<infer Prps>
? { Component: Comp, props: ComponentProps<Comp> & Record<Exclude<keyof PassedProps, keyof Prps>, never> }
: never
: never
} : never
const components = <
Comp extends React.JSXElementConstructor<any>,
Item extends { Component: Comp },
Components extends Record<string, Item>>(dictionary: Components & WithProps<Components>) => {}
Oyun alanı
Comp - türetilmiş bileşen
Öğe - çıkarılan sözlük öğesi, bileşen&özellikler nesnesi
Bileşenler - çıkarılan tüm argüman.
WithProps - geçirilen argümandaki her nesneyi döngüye sokar ve props nesnesinin bileşen propslarına atanabilir olup olmadığını kontrol eder. Eğer evet ise - props döndürür, aksi takdirde tüm geçersiz propsları never olarak reddeder.
components({
RedButton: {
Component: Button,
props: {
color: 'red'
}
},
BlueButton: {
Component: Button,
props: {
extra_prop:42, // DRAWBACK, no error
color: 'blue'
}
},
FullWidthCard: {
Component: Card,
props: {
variant_invalid_prop: 'full-width' // expected error
}
},
})
Ama bir dezavantaj var, bu fonksiyon ekstra özellikleri kabul edecek, örneğin extra_prop.
Not: Umarım biri, ekstra özelliklerin de geçersiz olacağı daha iyi bir çözüm bulur.
