
เข้ารหัสความล้มเหลวในโปรแกรมของคุณ
แพ็คเกจนี้มีประเภท Result ที่แสดงถึงความสำเร็จ ( Ok ) หรือความล้มเหลว ( Err )
สำหรับงานแบบอะซิงโครนัส neverthrow เสนอคลาส ResultAsync ที่ทำให้ Promise<Result<T, E>> และให้ระดับการแสดงออกและการควบคุมในระดับเดียวกันกับ Result<T, E>
ResultAsync thenable คือความหมายว่ามัน มีพฤติกรรมเหมือน Promise<Result> ... ยกเว้นคุณสามารถเข้าถึงวิธีการเดียวกันที่ Result ให้โดยไม่ต้อง await หรือ .then สัญญา! ตรวจสอบวิกิสำหรับตัวอย่างและแนวทางปฏิบัติที่ดีที่สุด
ต้องการดูตัวอย่างชีวิตจริงของวิธีการใช้ประโยชน์จากแพ็คเกจนี้สำหรับการจัดการข้อผิดพลาดหรือไม่? ดู repo นี้: 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 ในฐานะที่เป็นส่วนหนึ่งของโปรแกรม Bounty ของ neverthrow ผู้ใช้ mdbetancourt ได้สร้าง eslint-plugin-neverthrow เพื่อให้แน่ใจว่าข้อผิดพลาดจะไม่ถูกระงับ
ติดตั้งโดยการรัน:
> npm install eslint-plugin-neverthrow ด้วย eslint-plugin-neverthrow คุณถูกบังคับให้ใช้ผลลัพธ์ในหนึ่งในสามวิธีต่อไปนี้:
.match ตช์.unwrapOr._unsafeUnwrap สิ่งนี้ทำให้มั่นใจได้ว่าคุณจะจัดการข้อผิดพลาดของ Result ของคุณอย่างชัดเจน
ปลั๊กอินนี้เป็นหลักของการใช้แอตทริบิวต์ must-use ของ Rust
neverthrow เปิดเผยสิ่งต่อไปนี้:
ok ฟังก์ชั่นความสะดวกสบายในการสร้าง Ok ของ Resulterr ชั่นความสะดวกสบายเพื่อสร้างตัวแปรที่ Err ของ ResultOk และพิมพ์Err Class และพิมพ์Result เช่นเดียวกับเนมสเปซ / วัตถุที่จะเรียก Result.fromThrowable จากที่น่าจะเป็นผลลัพธ์ที่ผ่านมาResultAsyncokAsync เพื่อสร้าง ResultAsync ที่มี Result ประเภท OkerrAsync เพื่อสร้าง ResultAsync ที่มี Result ประเภท Err import {
ok ,
Ok ,
err ,
Err ,
Result ,
okAsync ,
errAsync ,
ResultAsync ,
fromAsyncThrowable ,
fromThrowable ,
fromPromise ,
fromSafePromise ,
safeTry ,
} from 'neverthrow' ตรวจสอบวิกิเพื่อขอความช่วยเหลือเกี่ยวกับวิธีการใช้ประโยชน์สูงสุดจาก 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 สร้างตัวแปร Err ของ Result
ลายเซ็น:
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 (วิธีการ) ส่งคืน true ถ้าผลลัพธ์เป็น Ok ตกลง
ลายเซ็น:
isOk ( ) : boolean { ... }⬆กลับไปด้านบน
Result.isErr (วิธีการ) ส่งคืน true หากผลลัพธ์เป็นตัวแปร Err
ลายเซ็น :
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 ทั้งสองฟังก์ชั่นจะต้องมี A ผลตอบแทนที่เหมือนกันmatch UNWraps 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 จะเทียบเท่ากับการผูกมัด map ด้วย unwrapOr :
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 จากนั้นคุณสามารถห่วงโซ่ผลลัพธ์ของ asyncMap โดยใช้ ResultAsync APIs (เช่น map , mapErr , andThen นั้น ฯลฯ )
ลายเซ็น:
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 จะแก้ไข Err เมื่อกลายเป็น Result โดยใช้ await หรือ .then()
⬆กลับไปด้านบน
Result.andTee (วิธีการ) ใช้ Result<T, E> และให้ Result<T, E> ผ่านไม่ว่าผลลัพธ์ของฟังก์ชั่นที่ผ่านมา นี่เป็นวิธีที่มีประโยชน์ในการจัดการกับผลข้างเคียงที่ความล้มเหลวหรือความสำเร็จไม่ควรส่งผลกระทบต่อ logics หลักของคุณเช่นการบันทึก
ลายเซ็น:
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 ยกเว้นคุณต้องส่งคืนผลลัพธ์
จากนั้นคุณสามารถห่วงโซ่ผลลัพธ์ของ asyncAndThrough โดยใช้ ResultAsync APIs (เช่น map , mapErr , andThen นั้น ฯลฯ )
ลายเซ็น:
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นั้นต้องการให้คุณโทรหาfromThrowableResultขึ้นราวกับว่ามันเป็นวิธีการคงที่ ดูตัวอย่างด้านล่าง
ชุมชน JavaScript ได้ตกลงกันในอนุสัญญาการขว้างข้อยกเว้น ดังนั้นเมื่อเชื่อมต่อกับไลบรารีของบุคคลที่สามจึงจำเป็นที่คุณต้องห่อรหัสบุคคลที่สามในบล็อกลอง / จับ
ฟังก์ชั่นนี้จะสร้างฟังก์ชั่นใหม่ที่ส่งคืน 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 ที่แตกต่างกันและยังสามารถรวมเข้าด้วยกันได้ โปรดทราบว่าคุณไม่สามารถรวมรายการที่มีทั้ง Result s และ ResultAsync s
ฟังก์ชั่นการรวมจะใช้รายการผลลัพธ์และส่งคืนผลลัพธ์เดียว หากผลลัพธ์ทั้งหมดในรายการ Ok ค่าส่งคืนจะเป็น Ok ที่มีรายการของค่า Ok ของแต่ละบุคคลทั้งหมด
หากเพียงหนึ่งในผลลัพธ์ในรายการคือ Err แล้วฟังก์ชั่นรวมจะส่งคืนค่า 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 )ตัวอย่างด้วย tuples:
/** @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 สร้างตัวแปร Ok ของ ResultAsync
ลายเซ็น:
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 สร้างตัวแปร Err ของ ResultAsync
ลายเซ็น:
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> โปรดทราบว่าสิ่งนี้สามารถปลอดภัยกว่าการใช้ผลลัพธ์ที่เกิดจากการเรียกใช้ฟังก์ชั่นเนื่องจากฟังก์ชั่นทั้งหมดที่ไม่ได้รับ 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 ยกเว้นว่ามันไม่ได้จัดการกับการปฏิเสธสัญญา ตรวจสอบให้แน่ใจว่าคุณรู้ว่าคุณกำลังทำอะไรมิฉะนั้นข้อยกเว้นที่ถูกโยนทิ้งไว้ในสัญญานี้จะทำให้ผลลัพธ์ถูกปฏิเสธแทนที่จะแก้ไขผลลัพธ์
ลายเซ็น:
// 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 (วิธีการ) แมป ResultAsync<T, E> เพื่อ ResultAsync<U, E> โดยการใช้ฟังก์ชันกับค่า Ok ที่มีอยู่โดยไม่ต้องแตะต้องค่า Err
ฟังก์ชั่นที่ใช้อาจเป็นแบบซิงโครนัสหรือแบบอะซิงโครนัส (ส่งคืน 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 (วิธีการ) แมป ResultAsync<T, E> เพื่อ ResultAsync<T, F> โดยการใช้ฟังก์ชันกับค่า Err ที่มีอยู่โดยไม่ต้องแตะต้องค่า Ok
ฟังก์ชั่นที่ใช้อาจเป็นแบบซิงโครนัสหรือแบบอะซิงโครนัส (ส่งคืน 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 แต่ส่งคืน 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 คือมันจะส่งคืน Promise เสมอเพราะลักษณะอะซิงโครนัสของ ResultAsync
ลายเซ็น:
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> ผ่านโดยไม่คำนึงถึงผลลัพธ์ของฟังก์ชั่นที่ผ่านมา นี่เป็นวิธีที่มีประโยชน์ในการจัดการกับผลข้างเคียงที่ความล้มเหลวหรือความสำเร็จไม่ควรส่งผลกระทบต่อ logics หลักของคุณเช่นการบันทึก
ลายเซ็น:
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 นั้น (มันลัดวงจรและส่งคืน 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 )ตัวอย่างด้วย tuples:
/** @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 ได้ โปรดค้นหาเอกสารที่ result.fromthrowable
⬆กลับไปด้านบน
fromAsyncThrowable การส่งออกระดับสูงสุดของ ResultAsync.fromThrowable ได้ โปรดค้นหาเอกสารที่ resultasync.fromthrowable
⬆กลับไปด้านบน
fromPromise การส่งออกระดับบนสุดของ ResultAsync.fromPromise โปรดค้นหาเอกสารที่ resultasync.frompromise
⬆กลับไปด้านบน
fromSafePromise การส่งออกระดับบนสุดของ ResultAsync.fromSafePromise โปรดค้นหาเอกสารที่ resultasync.fromafepromise
⬆กลับไปด้านบน
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 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> เพื่อระบุ 'return <RESULT> หากเป็น Err มิฉะนั้นจะประเมินค่า .value 'safeTry นอกจากนี้คุณยังสามารถใช้ฟังก์ชั่น Async Generator เพื่อส่งผ่านบล็อก 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
⬆กลับไปด้านบน
อินสแตนซ์ Result มีสองวิธีที่ไม่ปลอดภัยเรียกว่า _unsafeUnwrap และ _unsafeUnwrapErr ซึ่ง ควรใช้ในสภาพแวดล้อมการทดสอบเท่านั้น
_unsafeUnwrap ใช้ Result<T, E> และส่งคืน T เมื่อผลลัพธ์เป็น Ok มิฉะนั้นมันจะโยนวัตถุที่กำหนดเอง
_unsafeUnwrapErr ใช้ Result<T, E> และส่งคืน E เมื่อผลลัพธ์เป็น Err มิฉะนั้นจะโยนวัตถุที่กำหนดเอง
ด้วยวิธีนี้คุณสามารถทำอะไรบางอย่างเช่น:
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 นี่เป็นแหล่งที่มาของข้อผิดพลาด ตัวอย่าง: หนึ่ง dev throw s และ dev อื่นใช้ฟังก์ชั่นโดยไม่มีความรู้มาก่อนว่าฟังก์ชั่นจะโยน ดังนั้นและกรณีขอบถูกทิ้งไว้และตอนนี้คุณมีผู้ใช้ที่ไม่มีความสุขผู้บังคับบัญชาแมวแมว ฯลฯ
จากทั้งหมดที่กล่าวมามีกรณีการใช้งานที่ดีสำหรับการขว้างในโปรแกรมของคุณ แต่น้อยกว่าที่คุณคิด
โครงการ Neverthrow มีให้เป็นโอเพ่นซอร์สภายใต้ข้อกำหนดของใบอนุญาต MIT