
編碼失敗到您的程序中。
該軟件包包含一個代表成功( 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項目可作為開源。