Forget the Asynchronous let effect do it for you: เวลาเราเขียน Typescript function มันจะแยกกันชัดเจนไปเลยว่า function ที่เราสร้างต้องการให้เป็น Asynchronous ด้วย keyword async เวลาเราใช้ Effect ก็ไม่ต้องไปสนใจตรงนี้แล้ว เขียนแบบ Synchronous ไปได้เลย เดี๋ยว Effect runtime จัดการให้เอง
เวลาเอา functions หลายๆตัวมาทำงานต่อกัน code เราจะอ่านได้ง่ายมากๆ
Retry machanism: ถ้าหากว่า Effect เกิด Fail เราสามารถให้ Effect ทำงานใหม่อีกรอบ อีกกี่รอบก็กำหนดได้ โดยเว้นช่วงเวลาห่างกันเท่าไร ก่อนจะทำ retry ครั้งถัดไปก็กำหนดได้
ตัวอย่างเช่น มี Effect ที่ทำการดึง data จาก api ผ่าน fetch api แต่ว่าได้ error 500 Internal server error เราก็ให้ Effect ทำ retry เฉพาะส่วนนี้ได้ ไม่กระทบส่วนอื่นๆ ซึ่งการจะทำอะไรแบบนี้ได้ มันไม่ได้ง่ายเลยถ้าเราไม่มีตัวช่วย
pipe function(แทน pipe operator): Effect มี pipe function มาให้ใช้ ตรงนี้ผมชอบมาก เราสามารถเอา return value จาก function ก่อนหน้าส่งมาให้เป็น argument ใน function ถัดไปได้เลย
มี Immutable data structureArray, HashMap, HashSet, Trie etc etc พร้อม Composable API ที่ใช้งานง่ายมากขึ้น ถ้าใครเคยใช้ lib immutable, lodash ก็ใช้แทนได้เลย
Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
@param ― value A JavaScript value, usually an object or array, to be converted.
@param ― replacer A function that transforms the results.
@param ― space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
stringify(
const newUser: User
newUser))
11
}
12
catch (error) {
function(localvar)error: unknown
13
var console: Console
The console module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
A global console instance configured to write to process.stdout and
process.stderr. The global console can be used without importing the node:console module.
Warning: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s','world');
// Prints: hello world, to stdout
console.error(newError('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name ='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out =getStreamSomehow();
const err =getStreamSomehow();
const myConsole =new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s','world');
// Prints: hello world, to out
myConsole.error(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
Prints to stderr with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const code =5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr
If formatting elements (e.g. %d) are not found in the first string then
util.inspect() is called on each argument and the
resulting string values are concatenated. See util.format()
for more information.
@since ― v0.1.100
error(
function(localvar)error: unknown
error)
14
}
15
}
เมื่อดูที่ function register() เราจะเห็นว่ามันจะ return Promise<User> แต่ไม่ได้บอกว่าอาจจะเกิด Error นะ
เราก็เลยต้องใช้ try-catch block เข้ามาดักจับ Error ที่อาจจะเกิดขึ้น
ทีนี้เมื่อเราดูต่อที่ type ของ ตัวแปร error ใน catch block จะเห็นว่า type มันคือ unknown
หนึ่งในวิธีนั้นก็จะเป็นวิธีที่ใช้ Discriminated Unions Type
หลักการก็คือเราจะให้ function ที่มันอาจจะเกิด Error ได้ ให้มัน return Error as a value แทนที่จะ throw new Error()
แล้วจะบังคับให้คนที่เอา function เหล่านี้ไปใช้งานต่อต้องจัดการ handle error ซะก่อน
มาทำให้ function ที่อาจจะเกิด Error ทำการ return Error as a value กัน
เรามาทำ Discriminated type กันก่อน 👇
1
type
type Ok<A>={
type:"Ok";
value: A;
}
Ok<
function(typeparameter)AintypeOk<A>
A>={
2
type:"Ok"
type:"Ok"
3
value: A
value:
function(typeparameter)AintypeOk<A>
A
4
}
5
6
type
type Err<E>={
type:"Err";
error: E;
}
Err<
function(typeparameter)EintypeErr<E>
E>={
7
type:"Err"
type:"Err"
8
error: E
error:
function(typeparameter)EintypeErr<E>
E
9
}
10
11
type
type OkOrErr<A, E>= Ok<A>| Err<E>
OkOrErr<
function(typeparameter)AintypeOkOrErr<A, E>
A,
function(typeparameter)EintypeOkOrErr<A, E>
E>=
type Ok<A>={
type:"Ok";
value: A;
}
Ok<
function(typeparameter)AintypeOkOrErr<A, E>
A>|
type Err<E>={
type:"Err";
error: E;
}
Err<
function(typeparameter)EintypeOkOrErr<A, E>
E>
ส่วน function ที่เป็นมาจาก lib อื่นๆ หรือ function อะไรก็แล้วแต่ที่เราคุมไม่ได้อะ ให้เราเขียน Wrapper มาครอบมันซะ ถ้ามันจะมีปัญหาก็ให้ปัญหามันอยู่แค่ในนั้น แบบนี้ 👇
1
// assume hashPassword function from lib like bcrypt or argon2
Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
@param ― value A JavaScript value, usually an object or array, to be converted.
@param ― replacer A function that transforms the results.
@param ― space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
stringify(
const newUserResult: Ok<User>
newUserResult.
value: User
value),{
ResponseInit.status?: number
status:200})
78
}
79
catch (
function(localvar)error: unknown
error) {
80
var console: Console
The console module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
A global console instance configured to write to process.stdout and
process.stderr. The global console can be used without importing the node:console module.
Warning: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s','world');
// Prints: hello world, to stdout
console.error(newError('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name ='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out =getStreamSomehow();
const err =getStreamSomehow();
const myConsole =new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s','world');
// Prints: hello world, to out
myConsole.error(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
Prints to stderr with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const code =5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr
If formatting elements (e.g. %d) are not found in the first string then
util.inspect() is called on each argument and the
resulting string values are concatenated. See util.format()
for more information.
จะเห็นว่า function register() เอา function อื่นๆมาใช้งาน จะถูกบังคับให้ต้องดู type ก่อนว่าเป็น Ok หรือ Err ซึ่งเราก็ต้องจัดการกับ Error ก่อน สุดท้ายถ้าทุกอย่างผ่านไปได้ด้วยดีทั้งหมด เราก็ค่อย return ผลลัพธ์จริงๆที่ function register() ต้องส่งกลับไป
Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
@param ― value A JavaScript value, usually an object or array, to be converted.
@param ― replacer A function that transforms the results.
@param ― space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
stringify(
const newUserResult: Ok<User>
newUserResult.
value: User
value),{
ResponseInit.status?: number
status:200})
30
}
31
catch (
function(localvar)error: unknown
error) {
32
var console: Console
The console module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
A global console instance configured to write to process.stdout and
process.stderr. The global console can be used without importing the node:console module.
Warning: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s','world');
// Prints: hello world, to stdout
console.error(newError('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name ='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out =getStreamSomehow();
const err =getStreamSomehow();
const myConsole =new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s','world');
// Prints: hello world, to out
myConsole.error(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
Prints to stderr with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const code =5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr
If formatting elements (e.g. %d) are not found in the first string then
util.inspect() is called on each argument and the
resulting string values are concatenated. See util.format()
for more information.
@since ― v0.1.100
error(
function(localvar)error: unknown
error)
33
returnnew
var Response:new(body?: BodyInit,init?: ResponseInit)=> Response
Response(
var JSON: JSON
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed("Ok")
const ok: Effect.Effect<string,never,never>
4
จะเห็นว่าตัวแปร ok มี type เป็น Effect.Effect<string, never, never> หมายความว่า
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
@since ― 2.0.0
fail("Ok")
const notOk: Effect.Effect<never,string,never>
4
จะเห็นว่าตัวแปร notOk มี type เป็นแบบนี้ Effect.Effect<never, string, never> หมายความว่า
1
┌─── `never` -> ไม่มีทาง run ผ่านเพราะตรงนี้เป็น `never`
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
@since ― 2.0.0
@since ― 2.0.0
Effect<number,string>
ตัวอย่างเช่น
1
import{
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect}from"effect"
2
3
functionisNumberInFormOfString(
numberStr: string
numberStr:string):
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<out A,out E =never,out R =never>
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.parseInt(string: string, radix?: number): number
Converts A string to an integer.
@param ― string A string to convert into a number.
@param ― radix A value between 2 and 36 that specifies the base of the number in string.
If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
All other strings are considered decimal.
parseInt(
numberStr: string
numberStr)
5
if (
var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.isNaN(number: unknown): boolean
Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
to a number. Only values of the type number, that are also NaN, result in true.
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(
const num:number
num)
9
}
How to run Effect
เราจะเอา Effect ไป run ทำได้หลายวิธี
แต่ผมมักจะใช้อยู่ 2 วิธีหลักๆ
Effect.runSync()
Effect.runPromise()
การเลือกว่าจะใช้วิธี run แบบไหนมันจะมีวิธีอยู่
ขอให้เข้าใจก่อนว่าปกติเราจะเอา Effect ที่ได้จาก function หลายๆ function มาเรียงต่อกัน
เราจะใช้ Effect.runSync() เมื่อ ทุก function ที่เอามาเรียงต่อๆกัน ไม่มี function ใดเลยที่มี Promise เป็นส่วนประกอบ
เราจะใช้ Effect.runPromise() เมื่อมี function อย่างน้อย 1 function มี Promise เป็นส่วนประกอบ
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
@since ― 2.0.0
@since ― 2.0.0
Effect<number,string,never>{
4
const
const num:number
num=
var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.parseInt(string: string, radix?: number): number
Converts A string to an integer.
@param ― string A string to convert into a number.
@param ― radix A value between 2 and 36 that specifies the base of the number in string.
If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
All other strings are considered decimal.
parseInt(
numberStr: string
numberStr)
5
if (
var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.isNaN(number: unknown): boolean
Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
to a number. Only values of the type number, that are also NaN, result in true.
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
@since ― 2.0.0
@since ― 2.0.0
Effect<number,string,never>{
4
const
const num:number
num=
var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.parseInt(string: string, radix?: number): number
Converts A string to an integer.
@param ― string A string to convert into a number.
@param ― radix A value between 2 and 36 that specifies the base of the number in string.
If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
All other strings are considered decimal.
parseInt(
numberStr: string
numberStr)
5
if (
var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.isNaN(number: unknown): boolean
Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
to a number. Only values of the type number, that are also NaN, result in true.
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
Executes an effect synchronously and returns its result.
Use runSync when you are certain that the effect is purely synchronous and will not perform any asynchronous operations.
If the effect fails or contains asynchronous tasks, it will throw an error.
@example
import { Effect } from "effect"
// Define a synchronous effect
const program = Effect.sync(() => {
console.log("Hello, World!")
return 1
})
// Execute the effect synchronously
const result = Effect.runSync(program)
// Output: Hello, World!
Executes an effect synchronously and returns its result.
Use runSync when you are certain that the effect is purely synchronous and will not perform any asynchronous operations.
If the effect fails or contains asynchronous tasks, it will throw an error.
@example
import { Effect } from "effect"
// Define a synchronous effect
const program = Effect.sync(() => {
console.log("Hello, World!")
return 1
})
// Execute the effect synchronously
const result = Effect.runSync(program)
// Output: Hello, World!
ถ้าเรามี function หลายๆ function ที่ return Effect เหมือนกัน แล้วเราอยากเอา function เหล่านั้นมาทำงานร่วมกันเป็น function ที่ใหญ่ขึ้น แก้ปัญหาที่ใหญ่ขึ้น ให้ใช้ pipe() กับ Effect.andThen()
1
import{
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect,
functionpipe<A>(a: A):A(+19 overloads)
Pipes the value of an expression into a pipeline of functions.
This is useful in combination with data-last functions as a simulation of methods:
import { pipe } from "effect/Function"
// Alternatively, you can use the following import syntax, as pipe is also conveniently exported from the effect entry point:
// import { pipe } from "effect"
const length = (s: string): number => s.length
const double = (n: number): number => n * 2
const decrement = (n: number): number => n - 1
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
@since ― 2.0.0
@since ― 2.0.0
Effect<number,string>{
4
const
const num:number
num=
var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.parseInt(string: string, radix?: number): number
Converts A string to an integer.
@param ― string A string to convert into a number.
@param ― radix A value between 2 and 36 that specifies the base of the number in string.
If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
All other strings are considered decimal.
parseInt(
numberStr: string
numberStr)
5
if (
var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.
NumberConstructor.isNaN(number: unknown): boolean
Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
to a number. Only values of the type number, that are also NaN, result in true.
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
Creates an Effect that represents an asynchronous computation that might fail.
If the Promise returned by evaluate rejects, the error is caught and the effect fails with an UnknownException.
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
Overload with custom error handling:
Creates an Effect that represents an asynchronous computation that might fail, with custom error mapping.
If the Promise rejects, the catch function maps the error to an error of type E.
@example
import { Effect } from "effect"
// Fetching data from an API that may fail
const getTodo = (id: number) => Effect.tryPromise(() =>
fetch(https://jsonplaceholder.typicode.com/todos/${id})
)
import { pipe } from "effect/Function"
// Alternatively, you can use the following import syntax, as pipe is also conveniently exported from the effect entry point:
// import { pipe } from "effect"
const length = (s: string): number => s.length
const double = (n: number): number => n * 2
const decrement = (n: number): number => n - 1
Note: that Effect.catchAll will not recover from unrecoverable defects. To
recover from both recoverable and unrecoverable errors use
Effect.catchAllCause.
Executes an effect and returns a Promise that resolves with the result.
Use runPromise when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
@example
import { Effect } from "effect"
// Execute an effect and handle the result with a Promise
Effect.runPromise(Effect.succeed(1)).then(console.log) // Output: 1
// Execute a failing effect and handle the rejection
Effect.runPromise(Effect.fail("my error")).catch((error) => {
console.error("Effect failed with error:", error)
})
@since ― 2.0.0
runPromise(
const program: Effect.Effect<void,never,never>
program)
37
}
My recommendation about program flow while using Effect
import { pipe } from "effect/Function"
// Alternatively, you can use the following import syntax, as pipe is also conveniently exported from the effect entry point:
// import { pipe } from "effect"
const length = (s: string): number => s.length
const double = (n: number): number => n * 2
const decrement = (n: number): number => n - 1
Represents the completion of an asynchronous operation
Promise<string>
4
5
class
classHashPasswordError
HashPasswordErrorextends
import Data
Data.
constTaggedError:<"HashPasswordError">(tag:"HashPasswordError")=>new<A>(args: Equals<A,{}>extendstrue?void:{readonly [P inkeyof A as P extends"_tag"?never: P]: A[P];})=> YieldableError & ... 1 more ... & Readonly<...>
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
Creates an Effect that represents an asynchronous computation that might fail.
If the Promise returned by evaluate rejects, the error is caught and the effect fails with an UnknownException.
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
Overload with custom error handling:
Creates an Effect that represents an asynchronous computation that might fail, with custom error mapping.
If the Promise rejects, the catch function maps the error to an error of type E.
@example
import { Effect } from "effect"
// Fetching data from an API that may fail
const getTodo = (id: number) => Effect.tryPromise(() =>
fetch(https://jsonplaceholder.typicode.com/todos/${id})
)
import { pipe } from "effect/Function"
// Alternatively, you can use the following import syntax, as pipe is also conveniently exported from the effect entry point:
// import { pipe } from "effect"
const length = (s: string): number => s.length
const double = (n: number): number => n * 2
const decrement = (n: number): number => n - 1
Represents the completion of an asynchronous operation
Promise<
type User ={
id:string;
email:string;
hashedPassword:string;
}
User|null>
5
6
class
classFindOneByEmailError
FindOneByEmailErrorextends
import Data
Data.
constTaggedError:<"FindOneByEmailError">(tag:"FindOneByEmailError")=>new<A>(args: Equals<A,{}>extendstrue?void:{readonly [P inkeyof A as P extends"_tag"?never: P]: A[P];})=> YieldableError & ... 1 more ... & Readonly<...>
@since ― 2.0.0
TaggedError("FindOneByEmailError")<{
msg: string
msg:string,
error?: unknown
error?:unknown}>{}
7
8
functionfindOneByEmailWrap(
email: string
email:string):
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<out A,out E =never,out R =never>
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
Creates an Effect that represents an asynchronous computation that might fail.
If the Promise returned by evaluate rejects, the error is caught and the effect fails with an UnknownException.
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
Overload with custom error handling:
Creates an Effect that represents an asynchronous computation that might fail, with custom error mapping.
If the Promise rejects, the catch function maps the error to an error of type E.
@example
import { Effect } from "effect"
// Fetching data from an API that may fail
const getTodo = (id: number) => Effect.tryPromise(() =>
fetch(https://jsonplaceholder.typicode.com/todos/${id})
)
type Omit<T, K extendskeyofany>={ [P in Exclude<keyof T, K>]: T[P];}
Construct a type with the properties of T except for those in type K.
Omit<
type User ={
id:string;
email:string;
hashedPassword:string;
}
User,"id">):
interfacePromise<T>
Represents the completion of an asynchronous operation
Promise<
type User ={
id:string;
email:string;
hashedPassword:string;
}
User>
19
20
class
classSaveUserError
SaveUserErrorextends
import Data
Data.
constTaggedError:<"SaveUserError">(tag:"SaveUserError")=>new<A>(args: Equals<A,{}>extendstrue?void:{readonly [P inkeyof A as P extends"_tag"?never: P]: A[P];})=> YieldableError &{
...;
}& Readonly<...>
@since ― 2.0.0
TaggedError("SaveUserError")<{
error?: unknown
error?:unknown,
msg: string
msg:string}>{}
21
22
functionsaveUserWrap(
user: Omit<User,"id">
user:
type Omit<T, K extendskeyofany>={ [P in Exclude<keyof T, K>]: T[P];}
Construct a type with the properties of T except for those in type K.
Omit<
type User ={
id:string;
email:string;
hashedPassword:string;
}
User,"id">):
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<out A,out E =never,out R =never>
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
Creates an Effect that represents an asynchronous computation that might fail.
If the Promise returned by evaluate rejects, the error is caught and the effect fails with an UnknownException.
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
Overload with custom error handling:
Creates an Effect that represents an asynchronous computation that might fail, with custom error mapping.
If the Promise rejects, the catch function maps the error to an error of type E.
@example
import { Effect } from "effect"
// Fetching data from an API that may fail
const getTodo = (id: number) => Effect.tryPromise(() =>
fetch(https://jsonplaceholder.typicode.com/todos/${id})
)
import { pipe } from "effect/Function"
// Alternatively, you can use the following import syntax, as pipe is also conveniently exported from the effect entry point:
// import { pipe } from "effect"
const length = (s: string): number => s.length
const double = (n: number): number => n * 2
const decrement = (n: number): number => n - 1
Returns a Boolean value that indicates whether or not a pattern exists in a searched string.
@param ― string String on which to perform the search.
test(
email: string
email)
6
}
7
8
class
classEmailInvalid
EmailInvalidextends
import Data
Data.
constTaggedError:<"EmailInvalid">(tag:"EmailInvalid")=>new<A>(args: Equals<A,{}>extendstrue?void:{readonly [P inkeyof A as P extends"_tag"?never: P]: A[P];})=> YieldableError &{
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
@since ― 2.0.0
fail(new
constructor EmailInvalid<{
msg:string;
error?:unknown;
}>(args:{
readonlymsg:string;
readonlyerror?:unknown;
}):EmailInvalid
EmailInvalid({
msg: string
msg:"email is invalid"}))),
14
import Match
Match.
constwhen:<true,true,any,()=> Effect.Effect<boolean,never,never>>(pattern:true,f:()=> Effect.Effect<boolean,never,never>)=><I, F, A, Pr>(self: Match.Matcher<I, F,true, A, Pr,any>)=> Match.Matcher<...>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(true)),
15
import Match
Match.
constexhaustive:<I, F, A, Pr, Ret>(self: Match.Matcher<I, F,never, A, Pr, Ret>)=> [Pr] extends [never] ?(u: I)=> Unify<A>: Unify<A>
@since ― 1.0.0
exhaustive,
16
),
17
)
18
19
class
classPasswordInvalid
PasswordInvalidextends
import Data
Data.
constTaggedError:<"PasswordInvalid">(tag:"PasswordInvalid")=>new<A>(args: Equals<A,{}>extendstrue?void:{readonly [P inkeyof A as P extends"_tag"?never: P]: A[P];})=> YieldableError & ... 1 more ... & Readonly<...>
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
@since ― 2.0.0
fail(new
constructor PasswordInvalid<{
msg:string;
error?:unknown;
}>(args:{
readonlymsg:string;
readonlyerror?:unknown;
}):PasswordInvalid
PasswordInvalid({
msg: string
msg:"password need to be 8 characters long"}))),
28
import Match
Match.
constwhen:<true,true,any,()=> Effect.Effect<boolean,never,never>>(pattern:true,f:()=> Effect.Effect<boolean,never,never>)=><I, F, A, Pr>(self: Match.Matcher<I, F,true, A, Pr,any>)=> Match.Matcher<...>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(true)),
29
import Match
Match.
constexhaustive:<I, F, A, Pr, Ret>(self: Match.Matcher<I, F,never, A, Pr, Ret>)=> [Pr] extends [never] ?(u: I)=> Unify<A>: Unify<A>
Returns a Boolean value that indicates whether or not a pattern exists in a searched string.
@param ― string String on which to perform the search.
test(
password: string
password)
35
}
36
constisPasswordContainsSpecialCharEffect:(
password: string
password:string)=>
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<out A,out E =never,out R =never>
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
@since ― 2.0.0
fail(new
constructor PasswordInvalid<{
msg:string;
error?:unknown;
}>(args:{
readonlymsg:string;
readonlyerror?:unknown;
}):PasswordInvalid
PasswordInvalid({
msg: string
msg:"password need to be contains at least one special character"}))),
38
import Match
Match.
constwhen:<true,true,any,()=> Effect.Effect<boolean,never,never>>(pattern:true,f:()=> Effect.Effect<boolean,never,never>)=><I, F, A, Pr>(self: Match.Matcher<I, F,true, A, Pr,any>)=> Match.Matcher<...>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(true)),
39
import Match
Match.
constexhaustive:<I, F, A, Pr, Ret>(self: Match.Matcher<I, F,never, A, Pr, Ret>)=> [Pr] extends [never] ?(u: I)=> Unify<A>: Unify<A>
@since ― 1.0.0
exhaustive,
40
))
จากโค้ดด้านบน ผมสร้าง function ครอบ function ที่ใช้ verfiy email กับ verify password ไว้แล้วให้ return Effect
ผมใช้ flow() หลายคนอาจจะไม่คุ้นเคย ผมเล่าสั้นๆเกี่ยวกับ flow() ว่า มาจาก FP มันเป็นการเอา function เดิมที่มีอยู่แล้ว
มาเขียนเสริมเข้าไปกับอีก function หนึ่งกลายเป็น function ใหม่ที่รับ argument แบบเดิมเด๊ะๆ
พยายามอธิบายไม่รู้ว่าจะงงหนักกว่าเก่าหรือเปล่า เอาไว้ผมจะเขียน blog เล่าเกี่ยวกับ flow() นี้ให้แบบละเอียดอีกทีนะครับ note ว่ามันจะคล้ายๆกับ pipe()
ยังไม่หมด จะเห็นว่าผมใช้ Match ด้วย หลายคนก็อาจจะไม่คุ้นอีกแล้วหรอ
เอาสั้นๆมันก็เหมือนกับ switch-case รุ่น upgrade ที่ powerful มากๆ
ถ้ามีเวลาก็จะเขียน blog เกี่ยวกับตัวนี้ให้เช่นกันครับ
มาทำกันต่อ อีกนิดเดียวครับ
ผมจะทำ function isEmailExist() โดยจะเอาไปใช้ดูว่า email นี้มีอยู่ใน Database แล้วหรือยัง
1
// assume isEmailExist function from our another module that query the User table
Represents the completion of an asynchronous operation
Promise<
type User ={
id:string;
email:string;
hashedPassword:string;
}
User|null>
3
class
classFindOneByEmailError
FindOneByEmailErrorextends
import Data
Data.
constTaggedError:<"FindOneByEmailError">(tag:"FindOneByEmailError")=>new<A>(args: Equals<A,{}>extendstrue?void:{readonly [P inkeyof A as P extends"_tag"?never: P]: A[P];})=> YieldableError & ... 1 more ... & Readonly<...>
The Effect interface defines a value that lazily describes a workflow or job.
The workflow requires some context R, and may fail with an error of type E,
or succeed with a value of type A.
Effect values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an Effect value, you need a Runtime, which is a type that is capable
of executing Effect values.
Creates an Effect that represents an asynchronous computation that might fail.
If the Promise returned by evaluate rejects, the error is caught and the effect fails with an UnknownException.
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
Overload with custom error handling:
Creates an Effect that represents an asynchronous computation that might fail, with custom error mapping.
If the Promise rejects, the catch function maps the error to an error of type E.
@example
import { Effect } from "effect"
// Fetching data from an API that may fail
const getTodo = (id: number) => Effect.tryPromise(() =>
fetch(https://jsonplaceholder.typicode.com/todos/${id})
)
constTaggedError:<"UserAlreadyExist">(tag:"UserAlreadyExist")=>new<A>(args: Equals<A,{}>extendstrue?void:{readonly [P inkeyof A as P extends"_tag"?never: P]: A[P];})=> YieldableError & ... 1 more ... & Readonly<...>
Creates an Effect that represents a recoverable error.
This Effect does not succeed but instead fails with the provided error. The
failure can be of any type, and will propagate through the effect pipeline
unless handled.
Use this function when you want to explicitly signal an error in an Effect
computation. The failed effect can later be handled with functions like
catchAll
or
catchTag
.
@example
import { Effect } from "effect"
// Example of creating a failed effect
const failedEffect = Effect.fail("Something went wrong")
// Handle the failure
failedEffect.pipe(
Effect.catchAll((error) => Effect.succeed(Recovered from: ${error})),
Effect.runPromise
).then(console.log)
// Output: "Recovered from: Something went wrong"
The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like bind and let.
Here's how the do simulation works:
Start the do simulation using the Do value
Within the do simulation scope, you can use the bind function to define variables and bind them to Effect values
You can accumulate multiple bind statements to define multiple variables within the scope
Inside the do simulation scope, you can also use the let function to define variables and bind them to simple values
The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like bind and let.
Here's how the do simulation works:
Start the do simulation using the Do value
Within the do simulation scope, you can use the bind function to define variables and bind them to Effect values
You can accumulate multiple bind statements to define multiple variables within the scope
Inside the do simulation scope, you can also use the let function to define variables and bind them to simple values
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(new
var Response:new(body?: BodyInit,init?: ResponseInit)=> Response
Response(
e: EmailInvalid
e.
msg: string
msg,{
ResponseInit.status?: number
status:400})),
11
type FindOneByEmailError: (e: FindOneByEmailError) => Effect.Effect<Response,never,never>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(new
var Response:new(body?: BodyInit,init?: ResponseInit)=> Response
Response(
e: FindOneByEmailError
e.
msg: string
msg,{
ResponseInit.status?: number
status:500})),
12
type HashPasswordError: (e: HashPasswordError) => Effect.Effect<Response,never,never>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(new
var Response:new(body?: BodyInit,init?: ResponseInit)=> Response
Response(
e: HashPasswordError
e.
msg: string
msg,{
ResponseInit.status?: number
status:500})),
13
type PasswordInvalid: (e: PasswordInvalid) => Effect.Effect<Response,never,never>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(new
var Response:new(body?: BodyInit,init?: ResponseInit)=> Response
Response(
e: PasswordInvalid
e.
msg: string
msg,{
ResponseInit.status?: number
status:400})),
14
type SaveUserError: (e: SaveUserError) => Effect.Effect<Response,never,never>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(new
var Response:new(body?: BodyInit,init?: ResponseInit)=> Response
Response(
e: SaveUserError
e.
msg: string
msg,{
ResponseInit.status?: number
status:500})),
15
type UserAlreadyExist: (e: UserAlreadyExist) => Effect.Effect<Response,never,never>
Creates an Effect that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type A.
The effect does not fail and does not require any environmental context.
@example
import { Effect } from "effect"
// Creating an effect that succeeds with the number 42
const success = Effect.succeed(42)
@since ― 2.0.0
succeed(new
var Response:new(body?: BodyInit,init?: ResponseInit)=> Response
Executes an effect and returns a Promise that resolves with the result.
Use runPromise when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
@example
import { Effect } from "effect"
// Execute an effect and handle the result with a Promise
Effect.runPromise(Effect.succeed(1)).then(console.log) // Output: 1
// Execute a failing effect and handle the rejection
Effect.runPromise(Effect.fail("my error")).catch((error) => {
console.error("Effect failed with error:", error)
})
controller เป็นคนที่เอา register() มาใช้จะเป็นคนจัดการกับ Error ที่อาจจะเกิดขึ้น ผ่าน Effect.catchTags
Tag ที่เราใส่ใน Data.TaggedError จะมีประโยชน์ตอนนี้แหละ
เมื่อเราจัดการ handle Error แล้ว ไม่ได้ return Effect.fail แล้ว Effect จะทำการตัด fail Type ออกไปให้เราด้วย
ในตัวอย่างด้านบนเมื่อเรา handle error ได้ครบ เอา mouse ไป hover ที่ program จะเห็นว่ามันมี type เป็น Effect.Effect<Response, never>
ซึ่งส่วนที่ Error เป็น never ไปแล้ว
ถ้าเราเอา program ไปรันใน Effect.runPromise มันก็จะไม่มีทาง Error เพราเราได้ handle ไปหมดแล้ว
Conclusion
ถึงตรงนี้หลายๆคนน่าจะเริ่มสนใจ Effect กันแล้ว
ผมจะเขียน blog เกี่ยวกับการใช้งาน Effect มาเรื่อยๆนะครับ
เอาเป็น blog ไปก่อนละกัน ช่วงนี้ก็ยังอัดคลิปไม่ได้ เลี้ยงลูกคนเดียวไม่สะดวกเท่าไรครับ ถ้าอัดแล้วไม่ต้องตัดมันก็จะง่ายสำหรับผมเลย แต่ถ้าไม่ตัดคลิปมันจะยาว
มันก็เลยใช้พลังงานมาก เอ๊ะเหมือนบ่นให้ฟัง 😆😆
Thanks for being here ✨
ขอบคุณทุกคนที่เข้ามาอ่านจนจบนะครับ
blog นี้ค่อนข้างยาว ถ้ามีส่วนใดผิดพลาดสามารถชี้แนะกันได้นะครับ และขออภัยในความผิดพลาดนั้นล่วงหน้านะครับ