Typescript: установить ограничение на указанный c тип поиска универсального c типа объекта - PullRequest
0 голосов
/ 13 января 2020

Хорошо, вот в чем проблема. У меня есть следующие определения типов и функций:

export type compareFunction<T> = (t1: T, t2: T) => boolean

function createCompareFunctionCreator<P>(customCompare: compareFunction<P>) {
    return <
        T,
        K extends keyof T
    >(propName: K) => {
        return (t1: T, t2: T) => customCompare(t1[propName], t2[propName]) as compareFunction<P>
    }
}

У меня такой вопрос, как бы разместить конкретное ограничение, например T[propName] типа P?

Я пытался следующее:

function createCompareFunctionCreator<P>(customCompare: compareFunction<P>) {
    return <
        T extends { [keys in keyof T]: P },
        K extends keyof T
    >(propName: K) => {
        return (t1: T, t2: T) => customCompare(t1[propName], t2[propName]) as compareFunction<P>
    }
}

Но это заставляет ВСЕ свойства в T отображаться на тип P.

1 Ответ

1 голос
/ 13 января 2020

Заставить T иметь все свойства T

Проблема заключается в отсутствии связи между P и T. Мы можем решить это, но установив отношения. Рассмотрим следующий код:

export type compareFunction<T> = (t1: T, t2: T) => boolean

function createCompareFunctionCreator<P>(customCompare: compareFunction<P>) {
    return <
        T extends Record<K, P>, // pay attention here
        K extends keyof T
    >(propName: K) => {
        return (t1: T, t2: T) => customCompare(t1[propName], t2[propName])
    }
}

T extends Record<K, P> говорит, что наш тип T является объектом, все свойства которого имеют тип P. Благодаря этому мы можем сделать t1[propName], и мы знаем, что его тип P.

Заставляет T иметь свойства P с другими свойствами

Мы можем добиться этого с помощью некоторой дополнительной типизации рассмотрим:

// utility type which gives us only keys which values in T1 are T2
type OnlyKeysOfT<T1, T2> = {
    [K in keyof T1]: T1[K] extends T2 ? K : never
}[keyof T1]

function createCompareFunctionCreator<P>(customCompare: compareFunction<P>) {
    return <
        T extends Record<K, P>,
        K extends OnlyKeysOfT<T, P> = OnlyKeysOfT<T, P>,
    >(propName: K) => {
        return (t1: T, t2: T) => customCompare(t1[propName], t2[propName])
    }
}
// below only a is correct
createCompareFunctionCreator<string>((a,b) => true)<{a: string, b: number}>('a')
...