#typescript #typescript-typings
#typescript #typescript-типизации
Вопрос:
Я хочу определить DefaultProps
тип, который может находить все Undefinable
свойства из данного Props
типа компонента react, чтобы помочь мне определять defaultProps безопасным для типов способом:
export type UndefinableKeys<T> = Exclude<{
[key in keyof T]: undefined extends T[key] ? key : never
} [keyof T], undefined>;
import {UndefinableKeys} from "./UndefinableKeys";
export type DefaultProps<T> = {
[key in UndefinableKeys<T>]: Exclude<T[key], undefined>
}
Затем я определил вспомогательную функцию:
type OptionalPropsBuilder<P extends object> = {
withAll: (defaultProps: DefaultProps<P>) => DefaultProps<P>;
withSome: <DP extends Partial<DefaultProps<P>>>(defaultProps: DP) => Pick<DefaultProps<P>, keyof DP>;
};
export default function undefinableProps<P extends object>(): OptionalPropsBuilder<P> {
return {
withAll: (defaultProps) => defaultProps,
withSome: (defaultProps) => defaultProps,
};
}
Его использование будет похоже:
type Props = {
someProp1?: number,
someProp2?: number
}
const allDefaultProps = undefinableProps<Props>().withAll({
someProp1: 111,
someProp2: 222
})
const someDefaultProps = undefinableProps<Props>().withAll({
someProp1: 111,
// someProp2: 222
})
Но я обнаружил, что в методе есть ошибки компиляции withSome
, и не могу понять, почему после нескольких часов отладки.
- Почему
Pick<DefaultProps<P>, keyof DP>
ошибка компиляции вkeyof DP
части - Я попытался изменить его на:
Pick<DefaultProps<P>, Extract<keyof DefaultProps<P>, keyof DP>>
, но у него все та же ошибка компиляции
Комментарии:
1. Что, если вы измените
Pick<DefaultProps<P>, keyof DP>
наRequired<DP>
? Я думаю, это должно работать так, как вы хотите.
Ответ №1:
Из-за всего сопоставления typescript потерял знания, которые DP
являются подмножеством P
, и поэтому ключи DP
также должны быть ключами P
.
Хотя в этом нет необходимости, потому что Pick<DefaultProps<P>, Extract<keyof DefaultProps<P>, keyof DP>>
что на самом деле? Это то же самое, что сказать DP
. Просто верните DP
.
Очевидно, ваш код не совсем закончен, поэтому я еще немного поиграл с ним.
Мы определяем a PropFiller
для объекта P
как функцию, которая принимает набор допустимых props: P
и возвращает набор реквизитов, который выполняет P
, а также добавляет некоторое подмножество необязательных свойств по мере необходимости.
type PropFiller<P extends object, DP extends Partial<DefaultProps<P>>> = (props: P) => P amp; DP;
Мы реализуем это с помощью функции более высокого порядка, которая принимает набор defaultProps: DP
и возвращает PropFiller<P, DP>
функцию.
const createPropFiller = <P extends object, DP extends Partial<DefaultProps<P>>>(defaultProps: DP): PropFiller<P, DP> =>
(props: P) => ({
...defaultProps,
...props
});
Наш OptionalPropsBuilder
тип включает в себя два случая createPropFiller
. withAll
требуется, чтобы PropFiller
DefaultProps<P>
addsвсе время withSome
может принимать любое подмножество.
type OptionalPropsBuilder<P extends object> = {
withAll: (defaultProps: DefaultProps<P>) => PropFiller<P, DefaultProps<P>>;
withSome: <DP extends Partial<DefaultProps<P>>>(defaultProps: DP) => PropFiller<P, DP>;
};
function undefinableProps<P extends object>(): OptionalPropsBuilder<P> {
return {
withAll: createPropFiller,
withSome: createPropFiller,
};
}