type User = {
name?: string;
age?: number;
sex?: string;
};
type MyOmit<T, K extends PropertyKey> = { [P in Exclude<keyof T, K>]: T[P] };
type A = MyOmit<User, "name" | "age">;
type B = Omit<User, "name" | "age">;
Почему type A = {sex:string|undefined} и type B = {sex?:string|undefined}? Базовым методом обработки инструментов типа Omit является MyOmit. Почему результаты различаются?






Вы столкнулись с поведением TypeScript, известным как (не)гомоморфное сопоставление типов. Короче говоря, гомоморфное отображение означает, что модификаторы свойств, такие как readonly и необязательный (?), сохраняются в результате отображаемого типа.
Для получения дополнительной информации прочтите этот знаменитый вопрос: Что означает «гомоморфный отображаемый тип»?
Гомоморфный отображаемый тип создается, когда компилятор распознает, что отображаемый тип является существующим типом объекта (=User в вашем примере). Это обычно происходит, когда вы e. г. используйте синтаксис in keyof или in K, где K extends keyof T и T — это тип объекта, который необходимо сопоставить.
С другой стороны, негомоморфное отображение применяется, когда компилятор НЕ распознает существующий тип объекта. Это происходит при введении других условных типов, таких как Исключить или Извлечь. Таким образом, TypeScript не видит, что K на самом деле связано с User.
Как отмечено в microsoft/TypeScript/pull/12563 , вы можете обернуть MyOmit в Pick для обходного решения:
type User = {
name?: string;
age?: number;
sex?: string;
};
type MyOmit<T, K extends PropertyKey> = Pick<
T,
keyof { [P in Exclude<keyof T, K>]: T[P] }
>;
type A = MyOmit<User, "name" | "age">;
// ^? type A = { sex?: string | undefined; }
@Bergi Я просто скопировал и вставил исходное определение типа, чтобы продемонстрировать, что здесь решающее значение имеет Pick, а не какие-либо другие шаги по упрощению. Но спасибо за указание. Это приводит к тому же результату.
Почему бы просто не
Pick<T, Exclude<keyof T, K>>?