
编码失败到您的程序中。
该软件包包含一个代表成功( Ok )或失败( Err )的Result类型。
对于异步任务, neverthrow提供了一个ResultAsync类,该类别包裹了Promise<Result<T, E>> ,并为您提供与常规Result<T, E>相同的表达和控制。
ResultAsync thenable是可行的,这与本机Promise<Result> ...的行为完全相同...除非您可以访问Result提供的相同方法,而无需await或.then然后。查看Wiki以获取示例和最佳实践。
是否需要查看如何利用此软件包进行错误处理的现实示例?请参阅此仓库:https://github.com/parlez-vous/server
eslint-plugin-neverthrowResult )okerrResult.isOk (方法)Result.isErr (方法)Result.map (方法)Result.mapErr (方法)Result.unwrapOr (方法)Result.andThen 。Result.asyncAndThen 。Result.orElse (方法)Result.match (方法)Result.asyncMap 。Result.andTee (方法)Result.andThrough 。Result.asyncAndThrough 。Result.fromThrowable 。Result.combine (静态类方法)Result.combineWithAllErrors (静态类方法)Result.safeUnwrap()ResultAsync )okAsyncerrAsyncResultAsync.fromThrowable (静态类方法)ResultAsync.fromPromise (静态类方法)ResultAsync.fromSafePromise (静态类方法)ResultAsync.map (方法)ResultAsync.mapErr (方法)ResultAsync.unwrapOr (方法)ResultAsync.andThen (方法)ResultAsync.orElse (方法)ResultAsync.match (方法)ResultAsync.andTee (方法)ResultAsync.andThrough (方法)ResultAsync.combine (静态类方法)ResultAsync.combineWithAllErrors (静态类方法)ResultAsync.safeUnwrap()fromThrowablefromAsyncThrowablefromPromisefromSafePromisesafeTry > npm install neverthroweslint-plugin-neverthrow作为neverthrow S Bounty计划的一部分,用户MDBetancourt创建了eslint-plugin-neverthrow以确保错误不会被解释。
通过运行安装:
> npm install eslint-plugin-neverthrow借助eslint-plugin-neverthrow ,您被迫以以下三种方式之一消耗结果:
.match.unwrapOr._unsafeUnwrap这样可以确保您明确处理Result的错误。
该插件本质上是Rust must-use属性的移植。
neverthrow公开以下内容:
ok便利功能以创建Result的Ok变体err便利功能以创建Result的Err变体Ok类和类型Err类和类型Result类型以及命名空间 /对象可以从中调用Result.fromThrowable 。ResultAsync类okAsync便利函数创建包含Ok类型Result的ResultAsyncerrAsync便利函数创建一个包含Err类型Result的ResultAsync import {
ok ,
Ok ,
err ,
Err ,
Result ,
okAsync ,
errAsync ,
ResultAsync ,
fromAsyncThrowable ,
fromThrowable ,
fromPromise ,
fromSafePromise ,
safeTry ,
} from 'neverthrow'请查看Wiki,以了解如何充分利用neverthrow 。
如果您觉得这个包裹有用,请考虑赞助我或只是为我买咖啡!
Result ) ok构建Result的Ok变体
签名:
ok < T , E > ( value : T ) : Ok < T , E > { ... }例子:
import { ok } from 'neverthrow'
const myResult = ok ( { myData : 'test' } ) // instance of `Ok`
myResult . isOk ( ) // true
myResult . isErr ( ) // false⬆️回到顶部
err构建Result的Err变体
签名:
err < T , E > ( error : E ) : Err < T , E > { ... }例子:
import { err } from 'neverthrow'
const myResult = err ( 'Oh noooo' ) // instance of `Err`
myResult . isOk ( ) // false
myResult . isErr ( ) // true⬆️回到顶部
Result.isOk (方法)如果结果为Ok ,则返回true
签名:
isOk ( ) : boolean { ... }⬆️回到顶部
Result.isErr (方法)如果结果是Err变体,则返回true
签名:
isErr ( ) : boolean { ... }⬆️回到顶部
Result.map (方法)将Result<T, E>映射到Result<U, E>通过将函数应用于包含的Ok值,而Err值未触及。
此功能可用于构成两个函数的结果。
签名:
class Result < T , E > {
map < U > ( callback : ( value : T ) => U ) : Result < U , E > { ... }
}例子:
import { getLines } from 'imaginary-parser'
// ^ assume getLines has the following signature:
// getLines(str: string): Result<Array<string>, Error>
// since the formatting is deemed correct by `getLines`
// then it means that `linesResult` is an Ok
// containing an Array of strings for each line of code
const linesResult = getLines ( '1n2n3n4n' )
// this Result now has a Array<number> inside it
const newResult = linesResult . map (
( arr : Array < string > ) => arr . map ( parseInt )
)
newResult . isOk ( ) // true⬆️回到顶部
Result.mapErr (方法)将Result<T, E>映射到Result<T, F>通过将函数应用于包含的Err值,而Ok值未触及。
此功能可用于处理错误时通过成功的结果。
签名:
class Result < T , E > {
mapErr < F > ( callback : ( error : E ) => F ) : Result < T , F > { ... }
}例子:
import { parseHeaders } from 'imaginary-http-parser'
// imagine that parseHeaders has the following signature:
// parseHeaders(raw: string): Result<SomeKeyValueMap, ParseError>
const rawHeaders = 'nonsensical gibberish and badly formatted stuff'
const parseResult = parseHeaders ( rawHeaders )
parseResult . mapErr ( parseError => {
res . status ( 400 ) . json ( {
error : parseError
} )
} )
parseResult . isErr ( ) // true⬆️回到顶部
Result.unwrapOr (方法)解开Ok值,或者如果有Err ,返回默认值
签名:
class Result < T , E > {
unwrapOr < T > ( value : T ) : T { ... }
}例子:
const myResult = err ( 'Oh noooo' )
const multiply = ( value : number ) : number => value * 2
const unwrapped : number = myResult . map ( multiply ) . unwrapOr ( 10 )⬆️回到顶部
Result.andThen 。与上map相同的想法。除了您必须返回新Result 。
返回的值将是Result 。从v4.1.0-beta开始,您可以返回不同的错误类型(请参见下面的签名)。在v4.1.0-beta之前,错误类型无法区分。
这对于需要使用内部T值进行后续计算时很有用,但是该计算可能会失败。
另外, andThen确实是将Result<Result<A, E2>, E1>弄平到Result<A, E2>的工具(请参见下面的示例)。
签名:
class Result < T , E > {
// Note that the latest version lets you return distinct errors as well.
// If the error types (E and F) are the same (like `string | string`)
// then they will be merged into one type (`string`)
andThen < U , F > (
callback : ( value : T ) => Result < U , F >
) : Result < U , E | F > { ... }
}示例1:链接结果
import { err , ok } from 'neverthrow'
const sq = ( n : number ) : Result < number , number > => ok ( n ** 2 )
ok ( 2 )
. andThen ( sq )
. andThen ( sq ) // Ok(16)
ok ( 2 )
. andThen ( sq )
. andThen ( err ) // Err(4)
ok ( 2 )
. andThen ( err )
. andThen ( sq ) // Err(2)
err ( 3 )
. andThen ( sq )
. andThen ( sq ) // Err(3)示例2:嵌套嵌套结果
// It's common to have nested Results
const nested = ok ( ok ( 1234 ) )
// notNested is a Ok(1234)
const notNested = nested . andThen ( ( innerResult ) => innerResult )⬆️回到顶部
Result.asyncAndThen 。与上面的andThen上面的想法相同,除非您必须返回新的ResultAsync 。
返回的值将是ResultAsync 。
签名:
class Result < T , E > {
asyncAndThen < U , F > (
callback : ( value : T ) => ResultAsync < U , F >
) : ResultAsync < U , E | F > { ... }
}⬆️回到顶部
Result.orElse (方法)获取Err值并将其映射到Result<T, SomeNewType> 。这对于错误恢复很有用。
签名:
class Result < T , E > {
orElse < U , A > (
callback : ( error : E ) => Result < U , A >
) : Result < U | T , A > { ... }
}例子:
enum DatabaseError {
PoolExhausted = 'PoolExhausted' ,
NotFound = 'NotFound' ,
}
const dbQueryResult : Result < string , DatabaseError > = err ( DatabaseError . NotFound )
const updatedQueryResult = dbQueryResult . orElse ( ( dbError ) =>
dbError === DatabaseError . NotFound
? ok ( 'User does not exist' ) // error recovery branch: ok() must be called with a value of type string
//
//
// err() can be called with a value of any new type that you want
// it could also be called with the same error value
//
// err(dbError)
: err ( 500 )
)⬆️回到顶部
Result.match (方法)给定2个函数(一个用于Ok变体,一个用于Err变体)执行与Result变体匹配的函数。
匹配回调不必返回Result ,但是如果愿意,您可以返回Result 。
签名:
class Result < T , E > {
match < A , B = A > (
okCallback : ( value : T ) => A ,
errorCallback : ( error : E ) => B
) : A | B => { ... }
} match就像链接map和mapErr一样,具有match两个功能的区别必须具有相同的返回类型。 match map和mapErr之间的差异是:
match两个功能必须具有相同的返回类型Amatch将Result<T, E>拆开为A (匹配功能的返回类型)例子:
// map/mapErr api
// note that you DON'T have to append mapErr
// after map which means that you are not required to do
// error handling
computationThatMightFail ( ) . map ( console . log ) . mapErr ( console . error )
// match api
// works exactly the same as above since both callbacks
// only perform side effects,
// except, now you HAVE to do error handling :)
computationThatMightFail ( ) . match ( console . log , console . error )
// Returning values
const attempt = computationThatMightFail ( )
. map ( ( str ) => str . toUpperCase ( ) )
. mapErr ( ( err ) => `Error: ${ err } ` )
// `attempt` is of type `Result<string, string>`
const answer = computationThatMightFail ( ) . match (
( str ) => str . toUpperCase ( ) ,
( err ) => `Error: ${ err } `
)
// `answer` is of type `string`如果您不使用匹配回调中的错误参数,则match等于用unwrapOr链接map :
const answer = computationThatMightFail ( ) . match (
( str ) => str . toUpperCase ( ) ,
( ) => 'ComputationError'
)
// `answer` is of type `string`
const answer = computationThatMightFail ( )
. map ( ( str ) => str . toUpperCase ( ) )
. unwrapOr ( 'ComputationError' )⬆️回到顶部
Result.asyncMap 。类似于map ,除了两件事:
PromiseResultAsync然后,您可以使用ResultAsync API(例如map , mapErr , andThen等)链接asyncMap的结果
签名:
class Result < T , E > {
asyncMap < U > (
callback : ( value : T ) => Promise < U >
) : ResultAsync < U , E > { ... }
}例子:
import { parseHeaders } from 'imaginary-http-parser'
// imagine that parseHeaders has the following signature:
// parseHeaders(raw: string): Result<SomeKeyValueMap, ParseError>
const asyncRes = parseHeaders ( rawHeader )
. map ( headerKvMap => headerKvMap . Authorization )
. asyncMap ( findUserInDatabase )请注意,在上面的示例中,如果parseHeaders返回一个Err ,则不会调用.map和.asyncMap ,并且当使用await或.then()将结果变成Result时, asyncRes变量将解散为Err 。
⬆️回到顶部
Result.andTee (方法)取Result<T, E> ,然后让原始Result<T, E>无论传递函数的结果如何。这是处理副作用的方便方法,其失败或成功不应影响您的主要逻辑(例如记录)。
签名:
class Result < T , E > {
andTee (
callback : ( value : T ) => unknown
) : Result < T , E > { ... }
}例子:
import { parseUserInput } from 'imaginary-parser'
import { logUser } from 'imaginary-logger'
import { insertUser } from 'imaginary-database'
// ^ assume parseUserInput, logUser and insertUser have the following signatures:
// parseUserInput(input: RequestData): Result<User, ParseError>
// logUser(user: User): Result<void, LogError>
// insertUser(user: User): ResultAsync<void, InsertError>
// Note logUser returns void upon success but insertUser takes User type.
const resAsync = parseUserInput ( userInput )
. andTee ( logUser )
. asyncAndThen ( insertUser )
// Note no LogError shows up in the Result type
resAsync . then ( ( res : Result < void , ParseError | InsertError > ) => { e
if ( res . isErr ( ) ) {
console . log ( "Oops, at least one step failed" , res . error )
}
else {
console . log ( "User input has been parsed and inserted successfully." )
}
} ) )⬆️回到顶部
Result.andThrough 。类似于andTee ,除了:
签名:
class Result < T , E > {
andThrough < F > (
callback : ( value : T ) => Result < unknown , F >
) : Result < T , E | F > { ... }
}例子:
import { parseUserInput } from 'imaginary-parser'
import { validateUser } from 'imaginary-validator'
import { insertUser } from 'imaginary-database'
// ^ assume parseUseInput, validateUser and insertUser have the following signatures:
// parseUserInput(input: RequestData): Result<User, ParseError>
// validateUser(user: User): Result<void, ValidateError>
// insertUser(user: User): ResultAsync<void, InsertError>
// Note validateUser returns void upon success but insertUser takes User type.
const resAsync = parseUserInput ( userInput )
. andThrough ( validateUser )
. asyncAndThen ( insertUser )
resAsync . then ( ( res : Result < void , ParseErro | ValidateError | InsertError > ) => { e
if ( res . isErr ( ) ) {
console . log ( "Oops, at least one step failed" , res . error )
}
else {
console . log ( "User input has been parsed, validated, inserted successfully." )
}
} ) )⬆️回到顶部
Result.asyncAndThrough 。类似于和andThrough除非您必须返回结果。
然后,您可以使用ResultAsync API(例如map , mapErr , andThen等)链接asyncAndThrough的结果。
签名:
import { parseUserInput } from 'imaginary-parser'
import { insertUser } from 'imaginary-database'
import { sendNotification } from 'imaginary-service'
// ^ assume parseUserInput, insertUser and sendNotification have the following signatures:
// parseUserInput(input: RequestData): Result<User, ParseError>
// insertUser(user: User): ResultAsync<void, InsertError>
// sendNotification(user: User): ResultAsync<void, NotificationError>
// Note insertUser returns void upon success but sendNotification takes User type.
const resAsync = parseUserInput ( userInput )
. asyncAndThrough ( insertUser )
. andThen ( sendNotification )
resAsync . then ( ( res : Result < void , ParseError | InsertError | NotificationError > ) => { e
if ( res . isErr ( ) ) {
console . log ( "Oops, at least one step failed" , res . error )
}
else {
console . log ( "User has been parsed, inserted and notified successfully." )
}
} ) )⬆️回到顶部
Result.fromThrowable 。尽管结果不是实际的JS类,但是实现
fromThrowable方式的方式需要您将fromThrowable就像它是Result的静态方法一样。请参见下面的示例。
JavaScript社区已同意举行例外的公约。因此,当与第三方库接口时,必须将第三方代码包装在Try / Catch块中。
此功能将创建一个新功能,该功能在原始功能投掷时返回Err 。
不可能知道原始函数中丢弃的错误的类型,因此建议使用第二个参数errorFn映射抛出的内容。
例子:
import { Result } from 'neverthrow'
type ParseError = { message : string }
const toParseError = ( ) : ParseError => ( { message : "Parse Error" } )
const safeJsonParse = Result . fromThrowable ( JSON . parse , toParseError )
// the function can now be used safely, if the function throws, the result will be an Err
const res = safeJsonParse ( "{" ) ;⬆️回到顶部
Result.combine (静态类方法)尽管结果不是实际的JS类,但是结合
combine的实现方式需要您称为combine,就好像这是Result的静态方法一样。请参见下面的示例。
结合Result列表。
如果您熟悉Promise.all ,则组合功能在概念上相同。
在异质和均匀列表上的combine作品。这意味着您可以拥有包含不同Result s的列表,并且仍然可以结合起来。请注意,您不能结合包含Result s和ResultAsync s的列表。
联合函数列出了结果列表,并返回单个结果。如果列表中的所有结果都Ok ,则返回值将是一个Ok其中包含所有单个Ok值的列表。
如果仅列表中的结果之一是一个Err ,则组合函数返回该错误值(它短路并返回其找到的第一个err)。
正式演讲:
// homogeneous lists
function combine < T , E > ( resultList : Result < T , E > [ ] ) : Result < T [ ] , E >
// heterogeneous lists
function combine < T1 , T2 , E1 , E2 > ( resultList : [ Result < T1 , E1 > , Result < T2 , E2 > ] ) : Result < [ T1 , T2 ] , E1 | E2 >
function combine < T1 , T2 , T3 , E1 , E2 , E3 > => Result < [ T1 , T2 , T3 ] , E1 | E2 | E3 >
function combine < T1 , T2 , T3 , T4 , E1 , E2 , E3 , E4 > => Result < [ T1 , T2 , T3 , T4 ] , E1 | E2 | E3 | E4 >
// ... etc etc ad infinitum例子:
const resultList : Result < number , never > [ ] =
[ ok ( 1 ) , ok ( 2 ) ]
const combinedList : Result < number [ ] , unknown > =
Result . combine ( resultList )用元组的例子:
/** @example tuple(1, 2, 3) === [1, 2, 3] // with type [number, number, number] */
const tuple = < T extends any [ ] > ( ... args : T ) : T => args
const resultTuple : [ Result < string , never > , Result < string , never > ] =
tuple ( ok ( 'a' ) , ok ( 'b' ) )
const combinedTuple : Result < [ string , string ] , unknown > =
Result . combine ( resultTuple )⬆️回到顶部
Result.combineWithAllErrors (静态类方法)尽管结果不是实际的JS类,但是实现了
combineWithAllErrors使用的方式,需要您调用combineWithAllErrors,就好像这是Result的静态方法一样。请参见下面的示例。
像combine但没有短路。您可以获得输入结果列表的所有错误值的列表,而不仅仅是第一个错误值。
如果只有某些结果失败,新的组合错误列表将仅包含失败结果的错误值,这意味着无法保证新错误列表的长度。
功能签名:
// homogeneous lists
function combineWithAllErrors < T , E > ( resultList : Result < T , E > [ ] ) : Result < T [ ] , E [ ] >
// heterogeneous lists
function combineWithAllErrors < T1 , T2 , E1 , E2 > ( resultList : [ Result < T1 , E1 > , Result < T2 , E2 > ] ) : Result < [ T1 , T2 ] , ( E1 | E2 ) [ ] >
function combineWithAllErrors < T1 , T2 , T3 , E1 , E2 , E3 > => Result < [ T1 , T2 , T3 ] , ( E1 | E2 | E3 ) [ ] >
function combineWithAllErrors < T1 , T2 , T3 , T4 , E1 , E2 , E3 , E4 > => Result < [ T1 , T2 , T3 , T4 ] , ( E1 | E2 | E3 | E4 ) [ ] >
// ... etc etc ad infinitum示例用法:
const resultList : Result < number , string > [ ] = [
ok ( 123 ) ,
err ( 'boooom!' ) ,
ok ( 456 ) ,
err ( 'ahhhhh!' ) ,
]
const result = Result . combineWithAllErrors ( resultList )
// result is Err(['boooom!', 'ahhhhh!'])⬆️回到顶部
Result.safeUnwrap()弃用。您不再需要使用此方法。
允许解开Result或隐式返回Err ,从而减少样板。
⬆️回到顶部
ResultAsync ) okAsync构建ResultAsync的Ok变体
签名:
okAsync < T , E > ( value : T ) : ResultAsync < T , E >例子:
import { okAsync } from 'neverthrow'
const myResultAsync = okAsync ( { myData : 'test' } ) // instance of `ResultAsync`
const myResult = await myResultAsync // instance of `Ok`
myResult . isOk ( ) // true
myResult . isErr ( ) // false⬆️回到顶部
errAsync构建ResultAsync的Err变体
签名:
errAsync < T , E > ( error : E ) : ResultAsync < T , E >例子:
import { errAsync } from 'neverthrow'
const myResultAsync = errAsync ( 'Oh nooo' ) // instance of `ResultAsync`
const myResult = await myResultAsync // instance of `Err`
myResult . isOk ( ) // false
myResult . isErr ( ) // true⬆️回到顶部
ResultAsync.fromThrowable (静态类方法)类似于结果。可以从Promise转移的功能。
例子:
import { ResultAsync } from 'neverthrow'
import { insertIntoDb } from 'imaginary-database'
// insertIntoDb(user: User): Promise<User>
const insertUser = ResultAsync . fromThrowable ( insertIntoDb , ( ) => new Error ( 'Database error' ) )
// `res` has a type of (user: User) => ResultAsync<User, Error>请注意,这比使用函数调用结果使用ResultAsync.sysasync.sysync.sy.nc.,因为并非所有返回Promise的函数都是async ,因此它们可以同步丢弃错误,而不是返回被拒绝的Promise 。例如:
// NOT SAFE !!
import { ResultAsync } from 'neverthrow'
import { db } from 'imaginary-database'
// db.insert<T>(table: string, value: T): Promise<T>
const insertUser = ( user : User ) : Promise < User > => {
if ( ! user . id ) {
// this throws synchronously!
throw new TypeError ( 'missing user id' )
}
return db . insert ( 'users' , user )
}
// this will throw, NOT return a `ResultAsync`
const res = ResultAsync . fromPromise ( insertIntoDb ( myUser ) , ( ) => new Error ( 'Database error' ) )⬆️回到顶部
ResultAsync.fromPromise (静态类方法)将一个PromiseLike<T> (可能会扔到)转换为ResultAsync<T, E> 。
第二个参数处理承诺的拒绝案例,并将误差从unknown图映射到某种类型E中。
签名:
// fromPromise is a static class method
// also available as a standalone function
// import { fromPromise } from 'neverthrow'
ResultAsync . fromPromise < T , E > (
promise : PromiseLike < T > ,
errorHandler : ( unknownError : unknown ) => E )
) : ResultAsync < T , E > { ... }如果您使用的是事实上不知道的PromiseLike对象,那么请使用fromSafePromise ,以避免不得不传递冗余的errorHandler参数。
例子:
import { ResultAsync } from 'neverthrow'
import { insertIntoDb } from 'imaginary-database'
// insertIntoDb(user: User): Promise<User>
const res = ResultAsync . fromPromise ( insertIntoDb ( myUser ) , ( ) => new Error ( 'Database error' ) )
// `res` has a type of ResultAsync<User, Error>⬆️回到顶部
ResultAsync.fromSafePromise (静态类方法)与ResultAsync.fromPromise相同,只是它不能处理拒绝承诺。确保您知道自己在做什么,否则在此诺言中抛出的例外将导致Resultasync拒绝,而不是决心。
签名:
// fromPromise is a static class method
// also available as a standalone function
// import { fromPromise } from 'neverthrow'
ResultAsync . fromSafePromise < T , E > (
promise : PromiseLike < T >
) : ResultAsync < T , E > { ... }例子:
import { RouteError } from 'routes/error'
// simulate slow routes in an http server that works in a Result / ResultAsync context
// Adopted from https://github.com/parlez-vous/server/blob/2496bacf55a2acbebc30631b5562f34272794d76/src/routes/common/signup.ts
export const slowDown = < T > ( ms : number ) => ( value : T ) =>
ResultAsync . fromSafePromise < T , RouteError > (
new Promise ( ( resolve ) => {
setTimeout ( ( ) => {
resolve ( value )
} , ms )
} )
)
export const signupHandler = route < User > ( ( req , sessionManager ) =>
decode ( userSignupDecoder , req . body , 'Invalid request body' ) . map ( ( parsed ) => {
return createUser ( parsed )
. andThen ( slowDown ( 3000 ) ) // slowdown by 3 seconds
. andThen ( sessionManager . createSession )
. map ( ( { sessionToken , admin } ) => AppData . init ( admin , sessionToken ) )
} )
)⬆️回到顶部
ResultAsync.map (方法)通过将函数应用于包含的Ok值,使Err值未触及,将ResultAsync<T, E>映射到ResultAsync<U, E>
应用函数可以是同步的或异步的(返回Promise<U> ),而对返回类型没有影响。
此功能可用于构成两个函数的结果。
签名:
class ResultAsync < T , E > {
map < U > (
callback : ( value : T ) => U | Promise < U >
) : ResultAsync < U , E > { ... }
}例子:
import { findUsersIn } from 'imaginary-database'
// ^ assume findUsersIn has the following signature:
// findUsersIn(country: string): ResultAsync<Array<User>, Error>
const usersInCanada = findUsersIn ( "Canada" )
// Let's assume we only need their names
const namesInCanada = usersInCanada . map ( ( users : Array < User > ) => users . map ( user => user . name ) )
// namesInCanada is of type ResultAsync<Array<string>, Error>
// We can extract the Result using .then() or await
namesInCanada . then ( ( namesResult : Result < Array < string > , Error > ) => {
if ( namesResult . isErr ( ) ) {
console . log ( "Couldn't get the users from the database" , namesResult . error )
}
else {
console . log ( "Users in Canada are named: " + namesResult . value . join ( ',' ) )
}
} )⬆️回到顶部
ResultAsync.mapErr (方法)通过将函数应用于包含的Err值,使Ok值未触及,将ResultAsync<T, E>映射到ResultAsync<T, F>
应用函数可以是同步的或异步的(返回Promise<F> ),而对返回类型没有影响。
此功能可用于处理错误时通过成功的结果。
签名:
class ResultAsync < T , E > {
mapErr < F > (
callback : ( error : E ) => F | Promise < F >
) : ResultAsync < T , F > { ... }
}例子:
import { findUsersIn } from 'imaginary-database'
// ^ assume findUsersIn has the following signature:
// findUsersIn(country: string): ResultAsync<Array<User>, Error>
// Let's say we need to low-level errors from findUsersIn to be more readable
const usersInCanada = findUsersIn ( "Canada" ) . mapErr ( ( error : Error ) => {
// The only error we want to pass to the user is "Unknown country"
if ( error . message === "Unknown country" ) {
return error . message
}
// All other errors will be labelled as a system error
return "System error, please contact an administrator."
} )
// usersInCanada is of type ResultAsync<Array<User>, string>
usersInCanada . then ( ( usersResult : Result < Array < User > , string > ) => {
if ( usersResult . isErr ( ) ) {
res . status ( 400 ) . json ( {
error : usersResult . error
} )
}
else {
res . status ( 200 ) . json ( {
users : usersResult . value
} )
}
} )⬆️回到顶部
ResultAsync.unwrapOr (方法)解开Ok值”,或者如果有Err ,请返回默认值。
类似于Result.unwrapOr作品。unwrapor,但返回了Promise<T>而不是T 。
签名:
class ResultAsync < T , E > {
unwrapOr < T > ( value : T ) : Promise < T > { ... }
}例子:
const unwrapped : number = await errAsync ( 0 ) . unwrapOr ( 10 )
// unwrapped = 10⬆️回到顶部
ResultAsync.andThen (方法)与上map相同的想法。除了应用函数必须返回Result或ResultAsync 。
ResultAsync.andThen不管应用函数的返回类型如何,始终返回ResultAsync 。
这对于需要使用内部T值进行后续计算时很有用,但是该计算可能会失败。
andThen确实是将ResultAsync<ResultAsync<A, E2>, E1>弄平到ResultAsync<A, E2>工具(见下文)。
签名:
// Note that the latest version (v4.1.0-beta) lets you return distinct errors as well.
// If the error types (E and F) are the same (like `string | string`)
// then they will be merged into one type (`string`)
class ResultAsync < T , E > {
andThen < U , F > (
callback : ( value : T ) => Result < U , F > | ResultAsync < U , F >
) : ResultAsync < U , E | F > { ... }
}例子
import { validateUser } from 'imaginary-validator'
import { insertUser } from 'imaginary-database'
import { sendNotification } from 'imaginary-service'
// ^ assume validateUser, insertUser and sendNotification have the following signatures:
// validateUser(user: User): Result<User, Error>
// insertUser(user): ResultAsync<User, Error>
// sendNotification(user): ResultAsync<void, Error>
const resAsync = validateUser ( user )
. andThen ( insertUser )
. andThen ( sendNotification )
// resAsync is a ResultAsync<void, Error>
resAsync . then ( ( res : Result < void , Error > ) => {
if ( res . isErr ( ) ) {
console . log ( "Oops, at least one step failed" , res . error )
}
else {
console . log ( "User has been validated, inserted and notified successfully." )
}
} )⬆️回到顶部
ResultAsync.orElse (方法)获取Err值并将其映射到ResultAsync<T, SomeNewType> 。这对于错误恢复很有用。
签名:
class ResultAsync < T , E > {
orElse < U , A > (
callback : ( error : E ) => Result < U , A > | ResultAsync < U , A >
) : ResultAsync < U | T , A > { ... }
}⬆️回到顶部
ResultAsync.match (方法)给定2个函数(一个用于Ok变体,一个用于Err变体)执行与ResultAsync变体匹配的函数。
与Result.match的区别。匹配是由于ResultAsync ASASYNC的异步性质,它总是回报Promise 。
签名:
class ResultAsync < T , E > {
match < A , B = A > (
okCallback : ( value : T ) => A ,
errorCallback : ( error : E ) => B
) : Promise < A | B > => { ... }
}例子:
import { validateUser } from 'imaginary-validator'
import { insertUser } from 'imaginary-database'
// ^ assume validateUser and insertUser have the following signatures:
// validateUser(user: User): Result<User, Error>
// insertUser(user): ResultAsync<User, Error>
// Handle both cases at the end of the chain using match
const resultMessage = await validateUser ( user )
. andThen ( insertUser )
. match (
( user : User ) => `User ${ user . name } has been successfully created` ,
( error : Error ) => `User could not be created because ${ error . message } `
)
// resultMessage is a string⬆️回到顶部
ResultAsync.andTee (方法)采用ResultAsync<T, E> ,然后让原始的ResultAsync<T, E>无论传递函数的结果如何。这是处理副作用的方便方法,其失败或成功不应影响您的主要逻辑(例如记录)。
签名:
class ResultAsync < T , E > {
andTee (
callback : ( value : T ) => unknown
) : ResultAsync < T , E > => { ... }
}例子:
import { insertUser } from 'imaginary-database'
import { logUser } from 'imaginary-logger'
import { sendNotification } from 'imaginary-service'
// ^ assume insertUser, logUser and sendNotification have the following signatures:
// insertUser(user: User): ResultAsync<User, InsertError>
// logUser(user: User): Result<void, LogError>
// sendNotification(user: User): ResultAsync<void, NotificationError>
// Note logUser returns void on success but sendNotification takes User type.
const resAsync = insertUser ( user )
. andTee ( logUser )
. andThen ( sendNotification )
// Note there is no LogError in the types below
resAsync . then ( ( res : Result < void , InsertError | NotificationError > ) => { e
if ( res . isErr ( ) ) {
console . log ( "Oops, at least one step failed" , res . error )
}
else {
console . log ( "User has been inserted and notified successfully." )
}
} ) ) ⬆️回到顶部
ResultAsync.andThrough (方法)类似于andTee ,除了:
签名:
class ResultAsync < T , E > {
andThrough < F > (
callback : ( value : T ) => Result < unknown , F > | ResultAsync < unknown , F > ,
) : ResultAsync < T , E | F > => { ... }
}例子:
import { buildUser } from 'imaginary-builder'
import { insertUser } from 'imaginary-database'
import { sendNotification } from 'imaginary-service'
// ^ assume buildUser, insertUser and sendNotification have the following signatures:
// buildUser(userRaw: UserRaw): ResultAsync<User, BuildError>
// insertUser(user: User): ResultAsync<void, InsertError>
// sendNotification(user: User): ResultAsync<void, NotificationError>
// Note insertUser returns void upon success but sendNotification takes User type.
const resAsync = buildUser ( userRaw )
. andThrough ( insertUser )
. andThen ( sendNotification )
resAsync . then ( ( res : Result < void , BuildError | InsertError | NotificationError > ) => { e
if ( res . isErr ( ) ) {
console . log ( "Oops, at least one step failed" , res . error )
}
else {
console . log ( "User data has been built, inserted and notified successfully." )
}
} ) ) ⬆️回到顶部
ResultAsync.combine (静态类方法)结合ResultAsync s的列表。
如果您熟悉Promise.all ,则组合功能在概念上相同。
在异质和均匀列表上的combine作品。这意味着您可以拥有包含不同类型的ResultAsync的列表,并且仍然可以结合使用。请注意,您不能结合包含Result s和ResultAsync s的列表。
联合函数列出了结果列表,并返回单个结果。如果列表中的所有结果都Ok ,则返回值将是一个Ok其中包含所有单个Ok值的列表。
如果仅列表中的结果之一是一个Err ,则组合函数返回该错误值(它短路并返回其找到的第一个err)。
正式演讲:
// homogeneous lists
function combine < T , E > ( resultList : ResultAsync < T , E > [ ] ) : ResultAsync < T [ ] , E >
// heterogeneous lists
function combine < T1 , T2 , E1 , E2 > ( resultList : [ ResultAsync < T1 , E1 > , ResultAsync < T2 , E2 > ] ) : ResultAsync < [ T1 , T2 ] , E1 | E2 >
function combine < T1 , T2 , T3 , E1 , E2 , E3 > => ResultAsync < [ T1 , T2 , T3 ] , E1 | E2 | E3 >
function combine < T1 , T2 , T3 , T4 , E1 , E2 , E3 , E4 > => ResultAsync < [ T1 , T2 , T3 , T4 ] , E1 | E2 | E3 | E4 >
// ... etc etc ad infinitum例子:
const resultList : ResultAsync < number , never > [ ] =
[ okAsync ( 1 ) , okAsync ( 2 ) ]
const combinedList : ResultAsync < number [ ] , unknown > =
ResultAsync . combine ( resultList )用元组的例子:
/** @example tuple(1, 2, 3) === [1, 2, 3] // with type [number, number, number] */
const tuple = < T extends any [ ] > ( ... args : T ) : T => args
const resultTuple : [ ResultAsync < string , never > , ResultAsync < string , never > ] =
tuple ( okAsync ( 'a' ) , okAsync ( 'b' ) )
const combinedTuple : ResultAsync < [ string , string ] , unknown > =
ResultAsync . combine ( resultTuple )⬆️回到顶部
ResultAsync.combineWithAllErrors (静态类方法)像combine但没有短路。您可以获得输入结果列表的所有错误值的列表,而不仅仅是第一个错误值。
如果只有某些结果失败,新的组合错误列表将仅包含失败结果的错误值,这意味着无法保证新错误列表的长度。
功能签名:
// homogeneous lists
function combineWithAllErrors < T , E > ( resultList : ResultAsync < T , E > [ ] ) : ResultAsync < T [ ] , E [ ] >
// heterogeneous lists
function combineWithAllErrors < T1 , T2 , E1 , E2 > ( resultList : [ ResultAsync < T1 , E1 > , ResultAsync < T2 , E2 > ] ) : ResultAsync < [ T1 , T2 ] , ( E1 | E2 ) [ ] >
function combineWithAllErrors < T1 , T2 , T3 , E1 , E2 , E3 > => ResultAsync < [ T1 , T2 , T3 ] , ( E1 | E2 | E3 ) [ ] >
function combineWithAllErrors < T1 , T2 , T3 , T4 , E1 , E2 , E3 , E4 > => ResultAsync < [ T1 , T2 , T3 , T4 ] , ( E1 | E2 | E3 | E4 ) [ ] >
// ... etc etc ad infinitum示例用法:
const resultList : ResultAsync < number , string > [ ] = [
okAsync ( 123 ) ,
errAsync ( 'boooom!' ) ,
okAsync ( 456 ) ,
errAsync ( 'ahhhhh!' ) ,
]
const result = ResultAsync . combineWithAllErrors ( resultList )
// result is Err(['boooom!', 'ahhhhh!']) ResultAsync.safeUnwrap()弃用。您不再需要使用此方法。
允许解开Result或隐式返回Err ,从而减少样板。
⬆️回到顶部
fromThrowable最高级别的Result.fromThrowable 。请在结果上找到文档。
⬆️回到顶部
fromAsyncThrowable ResultAsync.fromThrowable的最高导出。请在resultasync中找到文档。
⬆️回到顶部
fromPromise ResultAsync.fromPromise的顶级导出。请在resultasync.frompromise上找到文档
⬆️回到顶部
fromSafePromise ResultAsync.fromSafePromise的最高导出。请在resultasync.fromsafromise上找到文档
⬆️回到顶部
safeTry用于隐式返回错误并减少样板。
假设我们正在编写返回Result的函数,在该功能中,我们调用了一些函数,这些功能也返回Result s,我们检查了这些结果,以查看我们应该继续前进还是流产。通常,我们会像以下内容一样编写。
declare function mayFail1 ( ) : Result < number , string > ;
declare function mayFail2 ( ) : Result < number , string > ;
function myFunc ( ) : Result < number , string > {
// We have to define a constant to hold the result to check and unwrap its value.
const result1 = mayFail1 ( ) ;
if ( result1 . isErr ( ) ) {
return err ( `aborted by an error from 1st function, ${ result1 . error } ` ) ;
}
const value1 = result1 . value
// Again, we need to define a constant and then check and unwrap.
const result2 = mayFail2 ( ) ;
if ( result2 . isErr ( ) ) {
return err ( `aborted by an error from 2nd function, ${ result2 . error } ` ) ;
}
const value2 = result2 . value
// And finally we return what we want to calculate
return ok ( value1 + value2 ) ;
}基本上,我们需要为每个结果定义一个常数,以检查是否还Ok ,并读取其.value或.error 。
通过安全性,我们可以说“如果Err ,则返回此处,否则将其解开并继续前进。”在一个表达中。
declare function mayFail1 ( ) : Result < number , string > ;
declare function mayFail2 ( ) : Result < number , string > ;
function myFunc ( ) : Result < number , string > {
return safeTry < number , string > ( function * ( ) {
return ok (
// If the result of mayFail1().mapErr() is an `Err`, the evaluation is
// aborted here and the enclosing `safeTry` block is evaluated to that `Err`.
// Otherwise, this `(yield* ...)` is evaluated to its `.value`.
( yield * mayFail1 ( )
. mapErr ( e => `aborted by an error from 1st function, ${ e } ` ) )
+
// The same as above.
( yield * mayFail2 ( )
. mapErr ( e => `aborted by an error from 2nd function, ${ e } ` ) )
)
} )
}要使用safeTry ,这些点如下。
yield* <RESULT>来陈述'返回<RESULT>如果是Err ,则可以对其.value进行评估'safeTry您也可以使用异步生成器函数通过异步块进行safeTry 。
// You can use either Promise<Result> or ResultAsync.
declare function mayFail1 ( ) : Promise < Result < number , string > > ;
declare function mayFail2 ( ) : ResultAsync < number , string > ;
function myFunc ( ) : Promise < Result < number , string > > {
return safeTry < number , string > ( async function * ( ) {
return ok (
// You have to await if the expression is Promise<Result>
( yield * ( await mayFail1 ( ) )
. mapErr ( e => `aborted by an error from 1st function, ${ e } ` ) )
+
// You can call `safeUnwrap` directly if its ResultAsync
( yield * mayFail2 ( )
. mapErr ( e => `aborted by an error from 2nd function, ${ e } ` ) )
)
} )
}有关更多信息,请参见#448和#444
⬆️回到顶部
Result实例有两种不安全的方法,恰当地称为_unsafeUnwrap和_unsafeUnwrapErr ,只能在测试环境中使用。
_unsafeUnwrap取Result<T, E>并在结果Ok时返回T ,否则会抛出自定义对象。
_unsafeUnwrapErr取Result<T, E>并在结果为Err时返回E ,否则会抛出自定义对象。
这样,您就可以做类似的事情:
expect ( myResult . _unsafeUnwrap ( ) ) . toBe ( someExpectation )但是,请注意, Result实例是可比的。因此,您不一定需要解开它们以在测试中提出期望。因此,您也可以做这样的事情:
import { ok } from 'neverthrow'
// ...
expect ( callSomeFunctionThatReturnsAResult ( "with" , "some" , "args" ) ) . toEqual ( ok ( someExpectation ) ) ;默认情况下,投掷值不包含堆栈跟踪。这是因为堆栈跟踪生成使嘲笑难以理解的错误消息。如果要生成堆栈跟踪,请使用配置对象致电_unsafeUnwrap和 /或_unsafeUnwrapErr :
_unsafeUnwrapErr ( {
withStackTrace : true ,
} )
// ^ Now the error object will have a `.stack` property containing the current stack如果您觉得这个包裹有用,请考虑赞助我或只是为我买咖啡!
尽管包裹被称为neverthrow ,但请不要从字面上看。我只是鼓励开发人员对他们所写的任何软件的人体工程学和用法进行更多思考。
Throw和catching与使用goto语句非常相似 - 换句话说;它更加努力地对您的程序进行理由。其次,通过使用throw您可以假设功能的呼叫者正在实现catch 。这是已知的错误来源。示例:一个开发throw S和另一个开发人员使用该功能,而无需事先知道该功能会抛出。因此,Edge Case已被遗忘了,现在您有不愉快的用户,老板,猫等。
话虽如此,肯定有一些很好的用例可以投入您的程序。但是比您想象的要少得多。
根据麻省理工学院许可条款,NeverThrow项目可作为开源。