Typescript: оценка типа универсальной функции

Есть ли какой-нибудь трюк, чтобы «оценить» тип общей функции?

Рассмотрим следующее:

type Arr = <A>() => A[]

type Ev<G, A> = ???

Вопрос. Можно ли заполнить ??? так, чтобы Ev<Arr, A> равнялось () => A[]? (по сравнению с <A>() => A[])


Еще несколько примеров желаемого поведения:

Ev<<A>() => A[], number>
    // should evaluate to
    // () => number[]

Ev<<A>() => string, number>
    // should evaluate to
    // () => string

Ev<<A>() => [string, A], { some: "thing" }>
    // should evaluate to
    // () => [string, { some: "thing" }]

Упрощенная версия вопроса будет такой: Можем ли мы определить

type EvNum<A> = ???

такой, что

EvNum<
   <X>() => X
> // should be `number`

EvNum<
   <X>() => X[]
> // should be `number[]`

EvNum<
   <X>() => [X, "hi"]
> // should be `[number, "hi"]`

EvNum<
   <X>() => SomeGenericType<X>
> // should be `SomeGenericType<number>`

EvNum<
   <X>() => "constant"
> // should be `"constant"`

person Gerrit Begher    schedule 27.03.2020    source источник
comment
Какое именно поведение вы ищете здесь? Было бы полезно, если бы вы могли привести более подробный пример, вы просто хотите получить возвращаемый тип переданной общей функции?   -  person Xetera    schedule 30.03.2020
comment
Я добавил несколько примеров   -  person Gerrit Begher    schedule 30.03.2020
comment
Невозможно понять, чего вы пытаетесь достичь. Предложите вам предоставить некоторые варианты использования для вашего требования.   -  person kctang    schedule 30.03.2020
comment
По сути, я хочу избавиться (указать) часть <A> на уровне типа. Мой вариант использования: общие типы для категории Клейсли монады без необходимости явно определять каждую категорию Клейсли вручную. Я хотел привести самый минимальный пример того, что мне нужно здесь.   -  person Gerrit Begher    schedule 30.03.2020
comment
github.com/gbegher/groth, если вам интересно.   -  person Gerrit Begher    schedule 30.03.2020
comment
У меня есть ощущение, что вам нужно будет использовать типы более высокого типа, чтобы сделать это, поскольку в какой-то момент ваш тип Arr (который является универсальным в типе Ev) должен быть параметризован другим универсальным, который, насколько я я знаю - это невозможно в Typescript.   -  person Xetera    schedule 31.03.2020
comment
Согласитесь с @Xetera, это действительно потребует параметризации параметризованного. См. здесь: github.com/Microsoft/TypeScript/issues/1213   -  person Raphael Medaer    schedule 31.03.2020
comment
@Xetera, @Raphael, я не уверен, что это одно и то же. Если я правильно понимаю, type T = <A>(a: A) => number не является универсальным типом, а interface T<A>{ (a:A): number } является универсальным типом.   -  person Gerrit Begher    schedule 25.04.2020


Ответы (2)


Что касается вашего первого вопроса, то они называются типами более высокого порядка и не поддерживаются в Typescript на момент этого ответа.

Высший тип — это просто тип, который абстрагируется от некоторого типа, который, в свою очередь, абстрагируется от другого типа. Итак, если вам нужен тип, который вы передаете в тип, чтобы абстрактно создать новый тип, это пример более высокого типа. А в ТС нельзя.

Вы не можете передать второй тип в общий тип и получить производный тип.

Ваш последний пример (упрощенный) буквально ReturnType, поэтому не уверен, что вы имеете в виду. Вполне можно придумать. Но вы не можете сделать тип, который приходит с этим.

type EvNum<T> = () => T;
type Arr<T> = T[];

function func<T>(param: EvNum<T>): T {
    return param();
}

let x1 = func(()=> 4); //number
let x2 = func(()=> [4]); //number[]
let x3 = func(()=> [4, "hi"] as const); //[4, "hi"]
let x4 = func(()=> "constant" as const); //"constant"
let cool: Arr<number> = [4, 5, 6];
let x5 = func(() => cool); //Arr<number>

Это передает ваши запрошенные типы

person Tim    schedule 13.04.2021
comment
Спасибо за пояснительный ответ. Таким образом, ответ кажется невозможным в TS. Однако, хотя в TS нет встроенной поддержки HKT, реализовать (некоторые функции) HKT вполне возможно. См., например, (github.com/gcanti/fp-ts). Однако одна функция, которую мне не удалось реализовать, — это лямбда-выражения на уровне типа. Вопрос направлен на это: если бы мы могли заменить ??? выражением с желаемыми свойствами, можно было бы получить некоторую форму лямбда на уровне типа. Поскольку HKT можно взломать вместе, я надеялся, что ??? тоже возможен. - person Gerrit Begher; 14.04.2021

Если я вас правильно понял, то должно быть:

type EV<T> = () => T;

В противном случае вопрос не имеет смысла или должен быть объяснен более подробно.

person Jan Bürling    schedule 06.04.2020
comment
Вы, кажется, неправильно прочитали / неправильно поняли вопрос. EV потребуется два параметра типа. - person Gerrit Begher; 25.04.2020