Почему тип «Выбрать <T, K> и опустить <T, K>» нельзя присвоить типу «T»?

Я обнаружил загадочную ошибку, скажем, я хочу иметь довольно бесполезную функцию, которая объединяет две дополняющие части объекта:

function foo<T extends object, K extends keyof T>(a: Pick<T, K>, b: Omit<T, K>): T {
    return { ...a, ...b } // TS2322: Type 'Pick<T, K> & Omit<T, K>' is not assignable to type 'T'. 'Pick<T, K> & Omit<T, K>' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'object'.
}

Я получил ошибку выше, в то время как код ниже явно работает:

interface Test {
    a: string,
    b: string
}

const a: Pick<Test, 'a'> = { a: 'a' }
const b: Omit<Test, 'a'> = { b: 'b' }

const t: Test = { ...a, ...b }

Редактировать 1:

function foo<T extends object, K extends keyof T>(a: Pick<T, K>, b: Omit<T, K>): T extends Pick<T, K> & Omit<T, K> ? T : any {
    const res: Pick<T, K> & Omit<T, K> = { ...a, ...b }
    return res // TS2322: Type 'Pick<T, K> & Omit<T, K>' is not assignable to type 'T extends Pick<T, K> & Omit<T, K> ? T : any'.
}

Редактировать 2:

function foo<T, K extends keyof T>(x: Pick<T, K> & Omit<T, K>): T {
    return x // TS2322: Type 'Pick<T, K> & Omit<T, K>' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'Pick<T, K> & Omit<T, K>'.
}

function bar<T, K extends keyof T>(x: T): Pick<T, K> & Omit<T, K> {
    return x // no issue
}

Это когда вы застреваете в сорняках машинописного текста вместо того, чтобы выполнять работу.

morganney 16.02.2023 15:05
Пройдите собеседование по Angular: Общие вопросы и ответы экспертов
Пройдите собеседование по Angular: Общие вопросы и ответы экспертов
Можете ли вы объяснить разницу между ngOnInit и конструктором в Angular?
Принципы SOLID в JavaScript с примерами
Принципы SOLID в JavaScript с примерами
Принцип единой ответственности подразумевает то, что:
Типы привязки данных в Angular
Типы привязки данных в Angular
Привязка данных автоматически поддерживает страницу в актуальном состоянии на основе состояния вашего приложения. Вы используете привязку данных,...
3 паттерна TypeScript, которые я использую в своей повседневной работе
3 паттерна TypeScript, которые я использую в своей повседневной работе
В TypeScript 2.0 в язык был добавлен модификатор readonly.
Мифический Angular - Миф Angular: стили компонентов
Мифический Angular - Миф Angular: стили компонентов
Это очень короткая и интересная для меня тема. В Angular каждый компонент может иметь свои собственные прикрепленные стили. Стили могут находиться в...
Подсказка RxJS [filter, skipWhile]
Подсказка RxJS [filter, skipWhile]
Эта подсказка описывает разницу между операторами filter и skipWhile из библиотеки RxJS .
6
1
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Здесь действительно есть вероятность несостоятельности. И Pick, и Omit реализованы как сопоставленные типы, и их результат может не содержать всех характеристик исходного типа.

Учти это:

interface Test {
    (arg: string): string
    a: string,
    b: string
}

const a: Pick<Test, 'a'> = { a: 'a' }
const b: Omit<Test, 'a'> = { b: 'b' }

const t: Test = { ...a, ...b }
//    ~ Type '{ b: string; a: string; }' provides no match 
//      for the signature '(arg: string): string'

Есть и еще одна проблема: компилятору не хватает возможности правильно проанализировать результат таких операций, как Pick<T, K>, когда T и K являются обобщенными типами. Типы T и K больше похожи на заполнители. Их конкретный тип неизвестен до тех пор, пока не будет вызвана функция, поэтому компилятор имеет лишь ограниченное представление о том, что будет означать пересечение Pick<T, K> с Omit<T, K>. Обсуждение похожей проблемы можно увидеть здесь по адресу #28884.


Детская площадка

Другие вопросы по теме