
プログラムに失敗をエンコードします。
このパッケージには、成功( Ok )または障害( Err )のいずれかを表すResultタイプが含まれています。
非同期タスクの場合、 neverthrow ResultAsyncクラスを提供し、 Promise<Result<T, E>>包み、通常のResult<T, E> 。
ResultAsync 、ネイティブのPromise<Result> Result await .then thenable <sults> ...例とベストプラクティスについては、Wikiをご覧ください。
エラー処理のためにこのパッケージを活用する方法の実際の例を見る必要がありますか?このリポジトリ:https://github.com/parlez-vous/serverを参照してください
eslint-plugin-neverthrowを使用しますResult )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 (static class method)ResultAsync.safeUnwrap()fromThrowablefromAsyncThrowablefromPromisefromSafePromisesafeTry > npm install neverthroweslint-plugin-neverthrowを使用しますneverthrow S Bountyプログラムの一環として、ユーザーMdbetancourtはeslint-plugin-neverthrowを作成して、エラーが処理されないようにしました。
実行によるインストール:
> npm install eslint-plugin-neverthrow eslint-plugin-neverthrowを使用すると、次の3つの方法のいずれかで結果を消費せざるを得ません。
.matchを呼び出します.unwrapOrを呼び出します._unsafeUnwrapを呼び出しますこれにより、 Resultのエラーを明示的に処理します。
このプラグインは、基本的にRustのmust-use属性の移植です。
neverthrow次のことを公開します。
okコンビニエンス関数ResultのOkバリアントを作成するerrコンビニエンス関数ResultのErrバリアントを作成するOkクラスとタイプErrクラスとタイプResultタイプと、 Result.fromThrowableを呼び出す名前空間 /オブジェクト。ResultAsyncクラスokAsyncコンビニエンス関数OkタイプのResultを含むResultAsyncを作成するerrAsyncコンビニエンス関数ErrタイプのResultを含むResultAsyncを作成する import {
ok ,
Ok ,
err ,
Err ,
Result ,
okAsync ,
errAsync ,
ResultAsync ,
fromAsyncThrowable ,
fromThrowable ,
fromPromise ,
fromSafePromise ,
safeTry ,
} from 'neverthrow' neverthrow最大限に活用する方法については、Wikiをご覧ください。
このパッケージが便利だと思う場合は、私をスポンサーするか、単にコーヒーを買うことを検討してください!
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 ( ) // falsetopに戻る
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 ( ) // truetopに戻る
Result.isOk (メソッド)結果がOkバリアントである場合、 trueを返します
サイン:
isOk ( ) : boolean { ... }topに戻る
Result.isErr (メソッド)結果がErrバリアントである場合、 trueを返します
サイン:
isErr ( ) : boolean { ... }topに戻る
Result.map (メソッド) Result<T, E>はResult<U, E>関数を含むOk値に適用し、 Err値を触れられないままにします。
この関数は、2つの関数の結果を構成するために使用できます。
サイン:
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 ( ) // truetopに戻る
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 ( ) // truetopに戻る
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 )topに戻る
Result.andThen (メソッド)上記のmapと同じアイデア。新しいResultを返す必要があることを除いて。
返された値がResultになります。 v4.1.0-betaの時点で、個別のエラータイプを返すことができます(以下の署名を参照)。 v4.1.0-betaの前に、エラータイプが明確ではありません。
これは、内部T値を使用して後続の計算を行う必要があるが、その計算が失敗する可能性がある場合に役立ちます。
さらに、 Result<Result<A, E2>, E1> Result<A, E2>にフラット化するためのツールとしてandThen役立ちます(以下の例を参照)。
サイン:
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 )topに戻る
Result.asyncAndThen (メソッド)新しいResultAsyncを返す必要があることを除いて、上記と同じアイデアとandThenです。
返された値はResultAsyncになります。
サイン:
class Result < T , E > {
asyncAndThen < U , F > (
callback : ( value : T ) => ResultAsync < U , F >
) : ResultAsync < U , E | F > { ... }
}topに戻る
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 )
)topに戻る
Result.match (メソッド) 2つの関数( Okバリアント用は1つ、 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と、両方の関数が同じ戻りタイプAを持っている必要がありますmatch 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' )topに戻る
Result.asyncMap (メソッド) 2つのことを除いてmapに似ています。
Promiseを返す必要がありますResultAsyncを返しますその後、 ResultAsync apis( 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は呼び出されず、 asyncRes変数はawaitまたは.then()を使用してResultに変換するとErrに解決します。
topに戻る
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." )
}
} ) )topに戻る
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." )
}
} ) )topに戻る
Result.asyncAndThrough (メソッド) resultAsyncを返す必要があることを除いて、 andThroughに似ています。
その後、 ResultAsync apis( 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." )
}
} ) )topに戻る
Result.fromThrowable 。結果は実際のJSクラスではありませんが、それが実装
fromThrowableれている方法では、Resultの静的な方法であるかのようにfromThrowableを呼び出す必要があります。以下の例を参照してください。
JavaScriptコミュニティは、例外を投げる慣習に同意しました。そのため、サードパーティのライブラリとインターフェースする場合、Try / Catchブロックでサードパーティのコードをラップすることが不可欠です。
この関数は、元の関数がスローされたときにErrを返す新しい関数を作成します。
元の関数にスローされたエラーのタイプを知ることはできないため、2番目の引数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 ( "{" ) ;topに戻る
Result.combine (静的クラスメソッド)結果は実際のJSクラスではありませんが、
combineが実装されている方法ではResultcombineを呼び出す必要があります。以下の例を参照してください。
Resultのリストを結合します。
Promise.allに精通している場合、Combine関数は概念的に同じように機能します。
不均一なリストと均一なリストの両方で作品combine 。これは、異なる種類のResultを含むリストを作成し、それらを結合できることを意味します。 ResultとResultAsync両方を含むリストを組み合わせることはできないことに注意してください。
Combine関数は結果のリストを取得し、単一の結果を返します。リスト内のすべての結果がOkである場合、返品値はすべての個々のOk値のリストを含むOkになります。
リストの結果の1つだけがErrである場合、Combine関数はその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 )topに戻る
Result.combineWithAllErrors (静的クラスメソッド)結果は実際のJSクラスではありませんが、
combineWithAllErrorsが実装された方法では、Resultの静的な方法であるかのようにcombineWithAllErrors呼び出す必要があります。以下の例を参照してください。
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!'])topに戻る
Result.safeUnwrap()非推奨。もうこの方法を使用する必要はありません。
Resultをアンラップするか、暗黙的にErrを返すことができ、それによりボイラープレートが削減されます。
topに戻る
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 ( ) // falsetopに戻る
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 ( ) // truetopに戻る
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.frompromiseを使用するよりも安全である可能性があることに注意してください。これは、 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' ) )topに戻る
ResultAsync.fromPromise (静的クラスメソッド) PromiseLike<T> (それが投げるかもしれない) ResultAsync<T, E>に変換します。
2番目の引数は、約束の拒絶ケースを処理し、 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オブジェクトを使用している場合は、冗長なerrorHandler引数を渡す必要がないように、 fromSafePromise使用してください。
例:
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>topに戻る
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 ) )
} )
)topに戻る
ResultAsync.map (メソッド) ResultAsync<T, E> Err OkしますResultAsync<U, E>
適用された関数は、リターンタイプに影響を与えずに、同期または非同期( Promise<U>返す)である可能性があります。
この関数は、2つの関数の結果を構成するために使用できます。
サイン:
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 ( ',' ) )
}
} )topに戻る
ResultAsync.mapErr (メソッド) ResultAsync<T, E> Ok ResultAsync<T, F>しますErr
適用された関数は、リターンタイプに影響を与えずに、同期または非同期( 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
} )
}
} )topに戻る
ResultAsync.unwrapOr (方法) Ok値を解除するか、 Errがある場合はデフォルトを返します。
Result.unwrapOrのように機能しますが、 Tの代わりにPromise<T> 。
サイン:
class ResultAsync < T , E > {
unwrapOr < T > ( value : T ) : Promise < T > { ... }
}例:
const unwrapped : number = await errAsync ( 0 ) . unwrapOr ( 10 )
// unwrapped = 10topに戻る
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." )
}
} )topに戻る
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 > { ... }
}topに戻る
ResultAsync.match (メソッド) 2つの関数( Okバリアント用は1つとErrバリアント用)が与えられた場合、 ResultAsyncバリアントに一致する関数を実行します。
Result.matchとの違いは、 ResultAsyncの非同期性のために常に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 stringtopに戻る
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." )
}
} ) ) topに戻る
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." )
}
} ) ) topに戻る
ResultAsync.combine (静的クラスメソッド) ResultAsyncのリストを組み合わせます。
Promise.allに精通している場合、Combine関数は概念的に同じように機能します。
不均一なリストと均一なリストの両方で作品combine 。これは、さまざまな種類のResultAsyncを含むリストを作成し、それらを組み合わせることができることを意味します。 ResultとResultAsync両方を含むリストを組み合わせることはできないことに注意してください。
Combine関数は結果のリストを取得し、単一の結果を返します。リスト内のすべての結果がOkである場合、返品値はすべての個々のOk値のリストを含むOkになります。
リストの結果の1つだけがErrである場合、Combine関数はその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 )topに戻る
ResultAsync.combineWithAllErrors (static class method) 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を返すことができ、それによりボイラープレートが削減されます。
topに戻る
fromThrowable Result.fromThrowableのトップレベルのエクスポート。結果でドキュメントを見つけてください
topに戻る
fromAsyncThrowable ResultAsync.fromThrowableのトップレベルのエクスポートから。 resultasync.fromthrowableでドキュメントを見つけてください
topに戻る
fromPromise ResultAsync.fromPromiseのトップレベルエクスポート。 resultasync.frompromiseでドキュメントを見つけてください
topに戻る
fromSafePromise ResultAsync.fromSafePromiseのトップレベルエクスポート。 resultasync.fromsAfpromiseでドキュメントを見つけてください
topに戻る
safeTry暗黙的にエラーを返し、ボイラープレートを減らすために使用されます。
Resultを返す関数を作成しているとしましょう。その関数では、 Resultも返す関数を呼び出し、それらの結果をチェックして、続行するか中止する必要があるかを確認します。通常、次のように書きます。
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ある場合はここに戻ることができます。たった1つの式で。
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を使用するには、ポイントは次のとおりです。
Errの場合は 'return <RESULT>を記載し、それ以外の場合は.valueに評価します'を使用して、 yield* <RESULT>を使用できます。safeTryに渡しますAsyncジェネレーター機能を使用して、 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を参照してください
topに戻る
Resultインスタンスには、テスト環境でのみ使用する必要がある_unsafeUnwrapと_unsafeUnwrapErrと呼ばれる2つの安全でないメソッドがあります。
_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 ) ) ;デフォルトでは、スロー値にはスタックトレースが含まれていません。これは、スタックトレースの生成がJestのエラーメッセージを理解しにくいためです。スタックトレースを生成したい場合は、構成オブジェクトを使用して_unsafeUnwrapおよび /または_unsafeUnwrapErr呼び出します。
_unsafeUnwrapErr ( {
withStackTrace : true ,
} )
// ^ Now the error object will have a `.stack` property containing the current stackこのパッケージが便利だと思う場合は、私をスポンサーするか、単にコーヒーを買うことを検討してください!
パッケージはneverthrowと呼ばれますが、文字通りこれを取得しないでください。私は、開発者に、彼らが書いているどんなソフトウェアと使用についてももう少し考えるように奨励しています。
Throwとcatching 、 gotoステートメントを使用することと非常によく似ています。それはあなたのプログラムについての推論をより難しくします。第二に、 throwを使用することにより、関数の発信者がcatchを実装していると仮定します。これは既知のエラーソースです。例:1つの開発者がスローthrow 、もう1つの開発者は、関数がスローする事前の知識なしに関数を使用します。したがって、エッジケースは未解決のままにされており、今では不幸なユーザー、ボス、猫などがいます。
とはいえ、プログラムを投入するための良いユースケースが間違いなくあります。しかし、あなたが思っているよりもはるかに少ない。
NeverThrowプロジェクトは、MITライセンスの条件の下でオープンソースとして利用できます。