Если вы хотите сохранить необязательный / только для чтения статус свойств в сопоставленном типе , вам нужно убедиться, что компилятор воспринимает сопоставление как гомоморфный .Я знаю два способа сделать это.
Один из них для отображения должен иметь форму {[K in keyof T]: ...}
, где вы непосредственно отображаете keyof T
для некоторого T
, общего или конкретного.Вы должны иметь что-то вроде in keyof
, появляющееся непосредственно в типе, иначе это не будет учитываться.
interface Foo {
optional?: string;
readonly viewonly: string;
}
type Homomorphic = { [K in keyof Foo]: 0 };
// type Homomorphic = {
// optional?: 0 | undefined;
// readonly viewonly: 0;
// }
type KeyOf<T> = keyof T
type NonHomomorphic = { [K in KeyOf<Foo>]: 0 };
// type NonHomomorphic = {
// optional: 0;
// viewonly: 0;
// }
Другим способом сделать это является сопоставление с параметром универсального типа K
, который был ограничен с keyof T
для другого параметра универсального типа T
.Итак:
type GenericConstraint<T, K extends keyof T> = { [P in K]: 0 };
type ConstrainedHomomorphic = GenericConstraint<Foo, keyof Foo>;
// type ConstrainedHomomorphic = {
// optional?: 0 | undefined;
// readonly viewonly: 0;
// }
type OnlySomeKeysStillHomomorphic = GenericConstraint<Foo, "viewonly">;
// type OnlySomeKeysStillHomomorphic = {
// readonly viewonly: 0;
// }
Этот последний метод был специально добавлен для получения частично отображенных типов, таких как Pick<T, K>
, для гомоморфности.И именно этот метод вам нужен, чтобы ваш фактический вариант использования работал:
// unchanged
type DataPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
// quick abort if T is a function or primitive
// otherwise pass to a homomorphic helper type
type DataPropertiesOnly<T> =
T extends Function ? never :
T extends object ? DPO<T, DataPropertyNames<T>> :
T
// homomorphic helper type
type DPO<T, KT extends keyof T> = {
[K in KT]
: T[K] extends (string | number | boolean) ? T[K]
: T[K] extends (infer A)[] ? DataPropertiesOnly<A>[]
: DataPropertiesOnly<T[K]>;
}
Я думаю, что это будет действовать так, как вы хотите.Хорошо, надеюсь, это поможет;удачи!