Typescript / Type Safe Curried Функции - PullRequest
       44

Typescript / Type Safe Curried Функции

3 голосов
/ 13 февраля 2020

Как безопасно набирать карри функции в машинописи? С особым вниманием к следующему примеру

interface Prop {
    <T, K extends keyof T>(name: K, object: T): T[K];
    <K>(name: K): <T>(object: T) => /* ?? */;
}

const prop: Prop = (key, object) => object[key];

const valid1 = prop('foo', { foo: 'hello' }); // string
const valid = prop('foo')({ foo: 'hello' });  // string

// `never`, since `baz` does not exist in { foo: string }
const invalid = prop('baz')({ foo: 'hello' }); // never

Ответы [ 2 ]

3 голосов
/ 13 февраля 2020

перегрузка функции

function prop<T, K extends keyof T>(name: K, obj: T): T[K]
function prop<K extends PropertyKey>(name: K):
    <T extends Record<K, unknown>>(obj: T) => T[K]
function prop(name: any, obj?: any) { 
    if (obj === undefined) {
        return (obj: any) => obj[name]
    } else {
        return obj[name]
    }
}
// weak types used in impl for simplicity, as they don't matter for the caller.
// also this function body is not really complex
const valid1 = prop('foo', { foo: 'hello1' }); // string
const valid2 = prop('foo')({ foo: 'hello2' });  // string
const invalid = prop('baz')({ foo: 'hello' }); // compile error, `baz` not in { foo: string } 

Образец


тип функции

interface Prop {
    <T, K extends keyof T>(name: K, obj: T): T[K];
    <K extends PropertyKey>(name: K): <T extends Record<K, unknown>>(obj: T) => T[K]
}

const prop: Prop = (name: any, obj?: any) => {
    if (obj === undefined) {
        return (obj: any) => obj[name]
    } else {
        return obj[name]
    }
}
// weak types used here for simplicity like in first solution
const valid1 = prop('foo', { foo: 'hello1' }); // string
const valid2 = prop('foo')({ foo: 'hello2' });  // string
const invalid = prop('baz')({ foo: 'hello' }); // never
console.log(valid1, valid2) // hello1 hello2

Пример

Примечание: Перегрузки функций и типы функций не могут использоваться полностью взаимозаменяемо (больше информации здесь или здесь ). В последнем случае может потребоваться аннотировать типы с помощью any в части реализации функции, чтобы учесть несовместимые типы возвращаемых значений в определенных сигнатурах вызовов - посмотрите эту площадку для примера.

0 голосов
/ 14 февраля 2020

Возможно, немного многословно, но делает то, что нужно:

interface Prop {
    <K extends PropertyKey, T extends {}>(name: K, object: T): K extends keyof T ? T[K] : undefined;
    <K extends PropertyKey>(name: K): <T extends {}>(object: T) => K extends keyof T ? T[K] : undefined;
}

declare const prop: Prop;

const invalid = prop('bar')({ foo: 'hello world' });
const valid = prop('foo')({ foo: 'hello world' });
const sLen = prop('length', 'Hello World');
const arity = prop('length')((a: number, b: number, c: number) => a + b + c);
...