Как по умолчанию использовать аргументы функции generi c с типами пересечений - PullRequest
3 голосов
/ 02 мая 2020

Я пытаюсь выяснить, почему следующий код не будет работать так, как я ожидаю. Тип пересечения, кажется, работает нормально (когда переопределяется внутри функции), однако использование его в качестве значения по умолчанию для аргумента generi c не подходит.

interface A {
    a: string
}

interface B {
    b: string
}

interface C {
    c: string
}

function returnStuff<T = A & B>(
    optionalReturnFn?: (value: T) => T): (value: T) => T {
    const defaultReturnFn = (value: T) => {
        value.a // <----- why does this a error
        return value
    }
        return optionalReturnFn ? optionalReturnFn : defaultReturnFn
}

function returnStuff2<T extends A & B>(
    optionalReturnFn?: (value: T) => T): (value: T) => T {
    const defaultReturnFn = (value: T) => {
        value.a // <----- while this one does not
        return value
    }
        return optionalReturnFn ? optionalReturnFn : defaultReturnFn
}

const bc: B & C = { b: 'b', c: 'c' } // <--- valid intersection type

// Works as expected when calling fn but DOESN't work as I'd expect internally to fn
returnStuff<B & C>((value) => { 
    return value
 })

// Doesn't work when calling fn but DOES work as expected internally to fn
returnStuff2<B & C>((value) => { 
    return value
 })

Вот TS Playground , если вы хотите поиграть с ошибками.

ОБНОВЛЕНИЕ : я закончил тем, что добавил защиту типа и использовал ее в определении функции returnStuff.

...
function isDefaultType<DefaultType>(
    record: any,
    keys: string[]
): record is DefaultType {
    return every(keys, (key) => key in record)
}

function returnStuff<T = A & B>(
    optionalReturnFn?: (value: T) => T): (value: T) => T {
    const defaultReturnFn = (value: T) => {
        if(isDefaultType<T>(value, ['a', 'b']) {
            value.a // <----- no longer throws an error
            return value
        }
    }
        return optionalReturnFn ? optionalReturnFn : defaultReturnFn
}

1 Ответ

3 голосов
/ 05 мая 2020

returnStuff

T = A & B показывает ошибку рядом с value.a, потому что вы только установили значение по умолчанию, но вы не ограничивали типы T через extends, T все еще может быть чем угодно, но если бы оно не было указано, это было бы A & B returnStuff<C>(v => v); - работает. returnStuff(v => v); - тоже работает. value.a терпит неудачу, потому что value может быть любым, строковым, неопределенным и т. Д. c.

правильный путь будет T extends A & B = A & B

returnStuff2

returnStuff2<B & C> не работает, потому что T extends A & B (не значение по умолчанию, а определенный базовый тип) требует свойства a, которое отсутствует при объединении B и C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...