将 Eithers 数组映射到值数组中的 Either
Mapping an array of Eithers to an Either of an array of values
我有一个 Either
类型,用于表示 Failure
和 Success
值,我想编写一个函数,它接受任意数量的 Either
s 和 returns 要么是序列中的第一个 Failure
,要么是一个新的 Success
,其值是展开的 Success
值的元组。该行为类似于 Promise.all()
.
我想我已经通过混合使用条件类型和映射类型来处理类型,但是我在实现实际功能来完成这项工作时遇到了问题。我不确定如何将输入的类型推断为任意长度的 Either
的元组。我仍然是一个 TypeScript 菜鸟,所以请耐心等待,让我知道是否有更好/更惯用的做事方式。
这是我目前所拥有的(和 TypeScript Playground Link):
type Either<E, T> = Failure<E, T> | Success<E, T>;
type Union<T> =
T extends Array<infer U> ? U :
T extends { [index: string]: infer U } ? U :
never;
type FailureType<T> = T extends Failure<infer U, infer V> ? U : never;
type SuccessType<T> = T extends Success<infer U, infer V> ? V : never;
type FailureTypesUnion<T> = Union<{ [K in keyof T]: FailureType<T[K]> }>;
type SuccessTypesAggregate<T> = { [K in keyof T]: SuccessType<T[K]> };
// This type represents the result type that `Result.sequence` should have.
type EitherTypesSequence<T> = Either<FailureTypesUnion<T>, SuccessTypesAggregate<T>>;
// this gives the desired type:
// `type Test = Failure<string | number | boolean> | Success<[boolean, string, number]>`
type Test = EitherTypesSequence<
[
Either<string, boolean>,
Either<number, string>,
Either<boolean, number>
]
>
class Result {
public static Ok<E, T>(value: T): Either<E, T> {
return new Success(value);
}
public static Err<E, T>(error: E): Either<E, T> {
return new Failure(error);
}
public static isSuccess<E, T>(target: Either<E, T>): target is Success<E, T> {
return target instanceof Success;
}
public static isFailure<E, T>(target: Either<E, T>): target is Failure<E, T> {
return target instanceof Failure;
}
public static sequence(
// ...args: ???
// How do I constrain the input to this function to be an array of Eithers?
// How to I infer the types of the Eithers as a tuple?
) {
// How wold I implement an angorithm here that plays nice with the types above?
}
}
// A Success class that represents the `right` path
class Success<E, T> {
private _value: T;
constructor(value: T) {
this._value = value;
}
public map<U>(fn: (v: T) => U): Either<E, U> {
return new Success(fn(this._value));
}
public chain<U, V>(fn: (v: T) => Either<U, V>): Either<E | U, V> {
return fn(this._value);
}
public either<U, V>(onFailure: (v: E) => U, onSuccess: (v: T) => V): U | V {
return onSuccess(this._value);
}
public get(): T {
return this._value;
}
}
// A Failure class that represents the `left` path
class Failure<E, T> {
private _value: E;
constructor(error: E) {
this._value = error;
}
public map<U>(fn: (v: T) => U): Either<E, U> {
return new Failure(this._value);
}
public chain<U, V>(fn: (v: T) => Either<U, V>): Either<E | U, V> {
return new Failure(this._value);
}
public either<U, V>(onFailure: (v: E) => U, onSuccess: (v: T) => V): U | V {
return onFailure(this._value);
}
public get(): E {
return this._value;
}
}
非常感谢任何帮助。
typescript 3.1 引入了丰富的元组? 3.2?我不记得了;但现在有了它们,所有函数参数都可以表示为元组(元组已经传播,可选参数就像函数一样)。
您可以像这样以元组形式获取输入。
如果你能给我更多关于 return 类型的信息,我也可以提供帮助。
interface Either<A> {
type: A
}
const sequence = <T extends Either<any>[]>(...args: T): T => {
// don't know whats supposed to be here till you tell me more.
return "" as any; // placeholder;
}
declare const EitherNumber: Either<number>;
declare const EitherString: Either<string>;
declare const EitherDate: Either<Date>;
const whatType = sequence(EitherNumber, EitherString, EitherDate) // [EitherNumber, EitherString, EitherDate] (tuple)
更新后它看起来像我留下了一个“我不知道这里有什么关于我遗漏了什么的字符串,也许你可以填写空白,但仅此而已。
type Success<E, T> = {e: E, t: T}; // doesn't matter but i don't understand two type parameters.
type Failure<E, T> = {e: E, t: T}; // doesn't matter but i dont understand two type parameters
type Either<E, T> = Failure<E, T> | Success<E, T>;
declare const EitherOne: Either<string, boolean>;
declare const EitherTwo: Either<number, string>;
declare const EitherThree: Either<boolean, number>;
type MapRight<T extends Either<any, any>[]> = {
[K in keyof T]: T[K] extends Either<any, infer Right> ? Right : never;
}
type GetLeft<T extends Either<any, any>> = [T] extends [Either<infer Left, infer Right>] ? Failure<Left, Right> : never;
const sequence = <T extends Either<any, any>[]>(...args: T): GetLeft<T[number]> | Success<"Dont Know what goes here", MapRight<T>>=> {
// don't know whats supposed to be here till you tell me more.
return "" as any; // placeholder;
}
const combined = sequence(EitherOne, EitherTwo, EitherThree); // Failure<string | number | boolean> | Success<"I dont know what goes here", [boolean, string, number]>
觉得这样没错。最终编辑。
type Success<E, T> = {e: E, t: T}; // doesn't matter but i don't understand two type parameters.
type Failure<E, T> = {e: E, t: T}; // doesn't matter but i dont understand two type parameters
type Either<E, T> = Failure<E, T> | Success<E, T>;
declare const EitherOne: Either<string, boolean>;
declare const EitherTwo: Either<number, string>;
declare const EitherThree: Either<boolean, number>;
type MapRight<T extends Either<any, any>[]> = {
[K in keyof T]: T[K] extends Either<any, infer Right> ? Right : never;
}
type GetRight<T extends Either<any, any>> = T extends Either<any, infer Right> ? Right : never;
type GetLeft<T extends Either<any, any>> = T extends Either<infer Left, any> ? Left : never;
const sequence = <T extends Either<any, any>[]>
(...args: T): Failure<GetLeft<T[number]>, GetRight<T[number]>> | Success<GetLeft<T[number]>, MapRight<T>> => {
// don't know whats supposed to be here till you tell me more.
return "" as any; // placeholder;
}
const combined = sequence(EitherOne, EitherTwo, EitherThree); // Failure<string | number | boolean> | Success<string | number | boolean, [boolean, string, number]>
我有一个 Either
类型,用于表示 Failure
和 Success
值,我想编写一个函数,它接受任意数量的 Either
s 和 returns 要么是序列中的第一个 Failure
,要么是一个新的 Success
,其值是展开的 Success
值的元组。该行为类似于 Promise.all()
.
我想我已经通过混合使用条件类型和映射类型来处理类型,但是我在实现实际功能来完成这项工作时遇到了问题。我不确定如何将输入的类型推断为任意长度的 Either
的元组。我仍然是一个 TypeScript 菜鸟,所以请耐心等待,让我知道是否有更好/更惯用的做事方式。
这是我目前所拥有的(和 TypeScript Playground Link):
type Either<E, T> = Failure<E, T> | Success<E, T>;
type Union<T> =
T extends Array<infer U> ? U :
T extends { [index: string]: infer U } ? U :
never;
type FailureType<T> = T extends Failure<infer U, infer V> ? U : never;
type SuccessType<T> = T extends Success<infer U, infer V> ? V : never;
type FailureTypesUnion<T> = Union<{ [K in keyof T]: FailureType<T[K]> }>;
type SuccessTypesAggregate<T> = { [K in keyof T]: SuccessType<T[K]> };
// This type represents the result type that `Result.sequence` should have.
type EitherTypesSequence<T> = Either<FailureTypesUnion<T>, SuccessTypesAggregate<T>>;
// this gives the desired type:
// `type Test = Failure<string | number | boolean> | Success<[boolean, string, number]>`
type Test = EitherTypesSequence<
[
Either<string, boolean>,
Either<number, string>,
Either<boolean, number>
]
>
class Result {
public static Ok<E, T>(value: T): Either<E, T> {
return new Success(value);
}
public static Err<E, T>(error: E): Either<E, T> {
return new Failure(error);
}
public static isSuccess<E, T>(target: Either<E, T>): target is Success<E, T> {
return target instanceof Success;
}
public static isFailure<E, T>(target: Either<E, T>): target is Failure<E, T> {
return target instanceof Failure;
}
public static sequence(
// ...args: ???
// How do I constrain the input to this function to be an array of Eithers?
// How to I infer the types of the Eithers as a tuple?
) {
// How wold I implement an angorithm here that plays nice with the types above?
}
}
// A Success class that represents the `right` path
class Success<E, T> {
private _value: T;
constructor(value: T) {
this._value = value;
}
public map<U>(fn: (v: T) => U): Either<E, U> {
return new Success(fn(this._value));
}
public chain<U, V>(fn: (v: T) => Either<U, V>): Either<E | U, V> {
return fn(this._value);
}
public either<U, V>(onFailure: (v: E) => U, onSuccess: (v: T) => V): U | V {
return onSuccess(this._value);
}
public get(): T {
return this._value;
}
}
// A Failure class that represents the `left` path
class Failure<E, T> {
private _value: E;
constructor(error: E) {
this._value = error;
}
public map<U>(fn: (v: T) => U): Either<E, U> {
return new Failure(this._value);
}
public chain<U, V>(fn: (v: T) => Either<U, V>): Either<E | U, V> {
return new Failure(this._value);
}
public either<U, V>(onFailure: (v: E) => U, onSuccess: (v: T) => V): U | V {
return onFailure(this._value);
}
public get(): E {
return this._value;
}
}
非常感谢任何帮助。
typescript 3.1 引入了丰富的元组? 3.2?我不记得了;但现在有了它们,所有函数参数都可以表示为元组(元组已经传播,可选参数就像函数一样)。
您可以像这样以元组形式获取输入。
如果你能给我更多关于 return 类型的信息,我也可以提供帮助。
interface Either<A> {
type: A
}
const sequence = <T extends Either<any>[]>(...args: T): T => {
// don't know whats supposed to be here till you tell me more.
return "" as any; // placeholder;
}
declare const EitherNumber: Either<number>;
declare const EitherString: Either<string>;
declare const EitherDate: Either<Date>;
const whatType = sequence(EitherNumber, EitherString, EitherDate) // [EitherNumber, EitherString, EitherDate] (tuple)
更新后它看起来像我留下了一个“我不知道这里有什么关于我遗漏了什么的字符串,也许你可以填写空白,但仅此而已。
type Success<E, T> = {e: E, t: T}; // doesn't matter but i don't understand two type parameters.
type Failure<E, T> = {e: E, t: T}; // doesn't matter but i dont understand two type parameters
type Either<E, T> = Failure<E, T> | Success<E, T>;
declare const EitherOne: Either<string, boolean>;
declare const EitherTwo: Either<number, string>;
declare const EitherThree: Either<boolean, number>;
type MapRight<T extends Either<any, any>[]> = {
[K in keyof T]: T[K] extends Either<any, infer Right> ? Right : never;
}
type GetLeft<T extends Either<any, any>> = [T] extends [Either<infer Left, infer Right>] ? Failure<Left, Right> : never;
const sequence = <T extends Either<any, any>[]>(...args: T): GetLeft<T[number]> | Success<"Dont Know what goes here", MapRight<T>>=> {
// don't know whats supposed to be here till you tell me more.
return "" as any; // placeholder;
}
const combined = sequence(EitherOne, EitherTwo, EitherThree); // Failure<string | number | boolean> | Success<"I dont know what goes here", [boolean, string, number]>
觉得这样没错。最终编辑。
type Success<E, T> = {e: E, t: T}; // doesn't matter but i don't understand two type parameters.
type Failure<E, T> = {e: E, t: T}; // doesn't matter but i dont understand two type parameters
type Either<E, T> = Failure<E, T> | Success<E, T>;
declare const EitherOne: Either<string, boolean>;
declare const EitherTwo: Either<number, string>;
declare const EitherThree: Either<boolean, number>;
type MapRight<T extends Either<any, any>[]> = {
[K in keyof T]: T[K] extends Either<any, infer Right> ? Right : never;
}
type GetRight<T extends Either<any, any>> = T extends Either<any, infer Right> ? Right : never;
type GetLeft<T extends Either<any, any>> = T extends Either<infer Left, any> ? Left : never;
const sequence = <T extends Either<any, any>[]>
(...args: T): Failure<GetLeft<T[number]>, GetRight<T[number]>> | Success<GetLeft<T[number]>, MapRight<T>> => {
// don't know whats supposed to be here till you tell me more.
return "" as any; // placeholder;
}
const combined = sequence(EitherOne, EitherTwo, EitherThree); // Failure<string | number | boolean> | Success<string | number | boolean, [boolean, string, number]>